{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "70292fb7-04e5-4b98-b240-030915e18869",
   "metadata": {},
   "source": [
    "# PRefLexOR Sample Training Script\n",
    "\n",
    "```bibtext\n",
    "@article{buehler2024PRefLexOR,\n",
    "      title={PRefLexOR: Preference-based Recursive Language Modeling for Exploratory Optimization of Reasoning and Agentic Thinking}, \n",
    "      author={Markus J. Buehler},\n",
    "      year={2024},\n",
    "      eprint={2410.12375},\n",
    "      archivePrefix={arXiv},\n",
    "      primaryClass={cs.AI},\n",
    "      url={https://arxiv.org/abs/2410.12375}, \n",
    "}\n",
    "```\n",
    "\n",
    "This script shows an example how the two training phases I and II can be implemented"
   ]
  },
  {
   "attachments": {
    "019fd573-4b5b-4076-8dde-679d30cb9121.png": {
     "image/png": "iVBORw0KGgoAAAANSUhEUgAABAkAAAH5CAIAAABsz/BoAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAECaADAAQAAAABAAAB+QAAAACngs1fAABAAElEQVR4AeydB3hUxdeHadJL6B0C0hEIHamhN+m9g4Dlj9IVaRKKgIhIUwQRAamCgBQpUkKVTugI0qW3IB0Uvjdev+tlkyzJZhN2N7998qxz586cOfNOiHNmzpmJ+ezZsxj6iIAIiIAIiIAIiIAIiIAIRHsCsaI9AQEQAREQAREQAREQAREQAREIIiDbQL8HIiACIiACIiACIiACIiACQQRkG+j3QAREQAREQAREQAREQAREIIiAbAP9HoiACIiACIiACIiACIiACAQRkG2g3wMREAEREAEREAEREAEREIEgArIN9HsgAiIgAiIgAiIgAiIgAiIQREC2gX4PREAEREAEREAEREAEREAEggjINtDvgQiIgAiIgAiIgAiIgAiIQBAB2Qb6PRABERABERABERABERABEQgiINtAvwciIAIiIAIiIAIiIAIiIAJBBGQb6PdABERABERABERABERABEQgiIBsA/0eiIAIiIAIiIAIiIAIiIAIBBGQbaDfAxEQAREQAREQAREQAREQgSACsg30eyACIiACIiACIiACIiACIhBEQLaBfg9EQAREQAREQAREQAREQASCCMg20O+BCIiACIiACIiACIiACIhAEAHZBvo9EAEREAEREAEREAEREAERCCIg20C/ByIgAiIgAiIgAiIgAiIgAkEEZBvo90AEREAEREAEREAEREAERCCIgGwD/R6IgAiIgAiIgAiIgAiIgAgEEZBtoN8DERABERABERABERABERCBIAJxhEEEXJNAQEDA/CXzdwXsOhpw9OLZi66ppLQSARFwjECGrBny+uQt7lO8Wf1mPj4+jglRLREQAREQAacTiPns2TOnC5VAEYgIgcDAwGbtm+0P2F+pfaVsPtmy+2RP450mIgJVVwREwNUIXD1z9VTAqdMBp9dPX1/Ip9D86fO9vLxcTUnpIwIiIALRkIBsg2g46C7d5R+X/Ni+ffuK7Su29GuZyCuRS+sq5URABCJM4F7gvTl+czZM37B4yeIqvlUiLE8CREAE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T/Y03mkcFKRqIiACLkng6pmrWAVnAs5waOlAv4Efdv/QJdWUUiIgAiIQ7QjINoh2Q+5GHfb3998asPVAwIHTZ067kdpS1TECjx4+evzwcdz4cePFj+eYBNVyIwLZvLMV9ClYxqeMr6+vG6ktVUVABETA4wnINvD4IVYHRcA9CPj5+Q0ePHjQoEEk3ENjaSkCIiACIiACHkdA8QYeN6TqkAiIgAiIgAiIgAiIgAg4REC2gUPYVEkEREAEREAEREAEREAEPI6AbAOPG1J1SAREQAREQAREQAREQAQcIiDbwCFsqiQCIiACIiACIiACIiACHkdAtoHHDak6JAIiIAIiIAIiIAIiIAIOEZBt4BA2VRIBERABERABERABERABjyMg28DjhlQdEgEREAEREAEREAEREAGHCMg2cAibKomACIiACIiACIiACIiAxxGQbeBxQ6oOiYAIiIAIiIAIiIAIiIBDBGQbOIRNlURABERABERABERABETA4wjINvC4IVWHREAEREAEREAEREAERMAhArINHMKmSiIgAiIgAiIgAiIgAiLgcQRkG3jckKpDIiACIiACIiACIiACIuAQAdkGDmFTJREQAREQAREQAREQARHwOAKyDTxuSNUhERABERABERABERABEXCIgGwDh7CpkgiIgAiIgAiIgAiIgAh4HAHZBh43pOqQCIiACIiACIiACIiACDhEQLaBQ9hUSQREQAREQAREQAREQAQ8joBsA48bUnVIBERABERABERABERABBwiINvAIWyqJAIiIAIiIAIiIAIiIAIeR0C2gccNqTokAiIgAiIgAiIgAiIgAg4RkG3gEDZVEgEREAEREAEREAEREAGPIyDbwOOGVB0SAREQAREQAREQAREQAYcIyDZwCJsqiYAIiIAIiIAIiIAIiIDHEZBt4HFDqg6JgAiIgAiIgAiIgAiIgEMEZBs4hE2VREAEREAEREAEREAERMDjCMg28LghVYdEQAREQAREQAREQAREwCECsg0cwqZKIiACIiACIiACIiACIuBxBGQbeNyQqkMiIAIiIAIiIAIiIAIi4BAB2QYOYVMlERABERABERABERABEfA4ArINPG5I1SEREAEREAEREAEREAERcIiAbAOHsKmSCIiACIiACIiACIiACHgcAdkGHjek6pAIiIAIiIAIiIAIiIAIOERAtoFD2FRJBERABERABERABERABDyOgGwDjxtSdUgEREAEREAEREAEREAEHCIg28AhbKokAiIgAiIgAiIgAiIgAh5HQLaBxw2pOiQCIiACIiACIiACIiACDhGQbeAQNlUSAREQAREQAREQAREQAY8jINvA44ZUHRIBERABERABERABERABhwjINnAImyqJgAiIgAiIgAiIgAiIgMcRkG3gcUOqDomACIiACIiACIiACIiAQwRkGziETZVEQAREQAREQAREQAREwOMIyDbwuCFVh0RABERABERABERABETAIQKyDRzCpkoiIALOIDB9+vSxY8eGKMnPz4+3Ib5SpgiIgAiIgAiIQCQRiBNJciVWBERABF5IoH379t7e3v7+/lYzIDAwsH79+mf++bxQggqIgAiIgAiIgAg4kYBsAyfClCgREIFwE2B/oEOHDj4+PjVq1KAyFgHWwu3bt7/77rtwy1IFERABERABERCBiBGI+ezZs4hJUG0REAERiBABjIGzZ88iIm3atFeuXCGRNWtWjIQICVVlERABERABERCB8BNQvEH4mamGCIiAUwmwdWDIMwwD0maOU9uRMBEQAREQAREQgRcQ0L7BCwDptQiIQBQQMLcOaEubBlEAXE2IgAiIgAiIQIgEtG8QIhZlioAIRCkB60aBNR2lSqgxERABERABEYj2BLRvEO1/BQRABFyDgLF1oE0D1xgNaSECIiACIhBNCWjfIJoOvLotAq5GwNgu0KaBq42L9BEBERABEYhWBHSGabQa7kjprHEaPQfSd+/ePTIa+OeY+zORIVkyXYoA+waFChXim+sOXEoxKRMZBBhoPpEhWTJFwBUI8H9GfsP536LWO1xhOKRDuAjIpyhcuFTYlsCSJUu4vorT6J3uCjL2i9H+/mv9N2718krinTWtbcN6FgERcGcCZ85eCQy841uhjK9vle49ertzV6S7CIRAgP85NmjQgBf8z5G7HX19fUMopCwRcEkCsg1ccljcRClWRMaNG4ey9erV42+fl5eXUxQPCNjTvl1r76ypundt4lMop5dXYqeIlRAREAGXIhAYeDdg/4mx4xecOXt9+oxZPj5FXUo9KSMCESQQEBDA/yU3btyInC+++IJ0BAWqughEDQHZBlHD2dNaYbeUVZD9+/cnS5Zs7NixbB04q4djvxjlN3jo9G/71q9bzlkyJUcERMCVCUyf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QgREIHwE+LfPXwD+DoSvmkqLgAiIgAg4lYBsA6filLCIEfDzGxF4+0n9Rv0CA+9GTJJqi4AIuA0B/r0H/au//YS/AG6jtBQVAREQAQ8lINvAQwfWbbvl77/FO1t+75xNlyyVa4HbjqIUF4EwE+BfOv/e+VfPv/0wV1JBERABERCByCIQ89mzZ5ElW3I9hUDMmDErVKjg7+8fZR3y91/Xvn27wMDbPoVyEIHAt1eyxFHWuhoSARGIVAKBt+9yVqn/xn18e3klmz59hq9v5UhtUcJFwGUJ8H9YdNNkzGUHKBoqJtsgGg56uLsc9baBoWJgYGBAwB5//7Xh1lgV3JDAmTPn+PH2zsKPG6ovlcNNwNe3io9PUS8vr3DXVAUR8CACsg08aDA9pCs6p8hDBtIju8GkgdVELSh65OAG75Sfn9+MGXN8fQeRCP5WOSIgAiIgAiIgAlFAQPEGUQBZTYiACIiACIiACIiACIiAGxCQbeAGgyQVRUAEREAEREAEREAERCAKCMg2iALIakIEREAEREAEREAEREAE3ICAbAM3GCSpKAIiIAIiIAIiIAIiIAJRQEC2QRRAVhMiIAIiIAIiIAIiIAIi4AYEZBu4wSBJRREQAREQAREQAREQARGIAgKyDaIAspoQAREQAREQAREQAREQATcgINvADQZJKoqACIiACIiACIiACIhAFBCQbRAFkN27CS4ndu8OSHsREAEREAEREAEREIGwEZBtEDZO0bhUQEBANO69ui4CIiACIiACIiAC0YiAbINoNNjqqgiIgAiIgAiIgAiIgAjYISDbwA4cvfqPgI+Pz38PSomACIiACIiACIiACHgiAdkGnjiqTu3TmTNnkOfl5eVUqRImAiIgAiIgAiIgAiLgcgRkG7jckLiaQoZt4O3t7WqKSR8REAEREAEREAEREAHnEpBt4FyeHijN39+fXsk28MChVZdEQAREQAREQARE4HkCsg2e56GnYASMfQNfX99gb5QhAiIgAiIgAiIgAiLgUQRkG3jUcDq9Mxxgevbs2axZszpdsgSKgAiIgAiIgAiIgAi4GgHZBq42Iq6lz/Tp01Goe/furqWWtBEBERABERABERABEYgEArINIgGqB4lcsmQJvalfv74H9UldEQEREAEREAEREAERCJmAbIOQuSgXAhgGOBQVKlRIgcj6fRABERABERABERCB6EDAzWwDnFtihuETkcBZ6tKCcThP2H8DHKsVdvkvpaSxadC+ffuX0roaFQEREAEREAEREAERiGICcaK4vQg2lyBBgmTJklmF3L59m8dEiRLFifNfXxInTmwto7RjBGQbOMZNtURABERABERABETATQn8N592iw6M+OdjVZU1fh6XL18ekb0Cq8D33nsP9/ocOXJYM1+YdqzWC8W+xAJ+fn7YXfXq1dONyC9xFNS0CIiACIiACIiACEQlATezDaIATePGjR1oxbFaDjQUNVU4unTw4MG0hYUQNS2qFREQAREQAREQAREQgZdOwM3iDcLIiwVvPmbhixcvmukXJpgWE2wQGBj4wpLWAo7VskpwnTR9Nw4mGjRokI+Pj+soJk1EQAREQAREQAREQAQilYBn2gbc1WVc1zVu3Lg0adLky5fPgPj48eMvvviiWLFi8ePHxxkpYcKEZcqU+f77762ICXeuWLEic30jc+zYsZTk+/z5823btk2ePDmPqVKleuutt27evGlWdKwW1RFC3UyZMhli8U26c+fOgAEDmJ1fvXrVlB+VCYKPOZ6oQoUK2jSISuxqSwREQAREQAREQAReOgFP9ikaNWpUnz59smfPnidPHkD/9ddftWvXXrt2Lel06dIR03zhwoVt/3yuXLnSu3dvO4Nx+fLl0qVLX79+vUiRIuxIHD58+Jtvvtm3b9+OHTtixQrVvnphrUuXLpUrV+7kyZMYBjlz5mTB/ssvv9yyZUvs2LH37t2LQWJHpUh6xWVnP/30E3CMQORIakViRUAEREAEREAEREAEXJBAqPNaF9Q1XCrdvXt32LBhy5YtY+a9YsUK6jLlxTBgyX/nzp1Myo8dO3bjxo1PPvmEVxMmTLAvfMyYMUQnnzt3buvWrYcOHVq1ahXT993/fOxUfGGtzp07o16JEiVOnTp1/PhxTJQFCxaQwDCwIzbyXmGNdOjQAflYCApBjjzOkiwCIiACIiACIiACrknAY22Dv//+u2vXrm+88YbJ/d69e/jJ9O3bt3jx4kZm3Lhxe/bsSdoanGCWtyYo+cMPP6ROndrIrF69evny5Unbj2SwX+vIkSMYLfg1LV261LhcjN0DYppxKLI2HTVptiw46KlHjx40h9uVEW8QNU2rFREQAREQAREQAREQARch4LG2AXwbNmxopUy0AEHGhjFg5DMhnjJlirVM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QUBA0XE/TveXOWueIhBeBGQ3CC+S6ie8CMhuEF4ko1Y/KAO4AJUuXfrYsWP58uUj/CC81o9wEBjYDNeCbt3nHz12Mby6VT8iIAI+SIB/4/xL599727afSjHwwRekKYmACERBArIbRMGXHp5LRiv48ssv6RE9wRzuGC69o3i0bdN0+/adV65e4zgq2RDChao6EQHfIYCtYPnKgwnix2OjYdDg4XIl8p1Xo5l4mYDsBl4GruGeSEC6wRMRqcETCOBfROABH0+cl0w8A/2Ho9bxhMXodsQR4EXzQVLkE3Gz0MheIoBTIi9a5z15CbeG8WEC0g18+OVE0alJN4iiLz58l20ikvW/+fClGtV6Mzaorl27hqOLWlRjqPWKgAj4HQHpBn73yiL9hKNH+hVqgV4gIK3AC5A1hAiIgAiIgAiIgAh4moBikT1NWP2LgAiIgAiIgAiIgAiIgH8QkG7gH+9JsxQBERABERABERABERABTxOQbuBpwupfBERABERABERABERABPyDgHQD/3hPmqUIiIAIiIAIiIAIiIAIeJqAdANPE1b/IiACIiACIiACIiACIuAfBKQb+Md70ixFQAREQAREQAREQAREwNMEpBt4mrD6FwEREAEREAEREAEREAH/ICDdwD/ek2YpAiIgAiIgAiIgAiIgAp4mIN3A04TVvwiIgAiIgAiIgAiIgAj4BwHpBv7xnjRLERABERABERABERABEfA0AekGnias/kVABERABERABERABETAPwhIN/CP96RZioAIiIAIiIAIiIAIiICnCUg38DRh9S8CIiACIiACIiACIiAC/kFAuoF/vCfNUgREQAREQAREQAREQAQ8TUC6gacJq38REAEREAEREAEREAER8A8C0g384z1pliIgAiIgAiIgAiIgAiLgaQLSDTxNWP2LgAiIgAiIgAiIgAiIgH8QkG7gH+9JsxQBERABERABERABERABTxOQbuBpwupfBERABERABERABERABPyDgHQD/3hPmqUIiIAIiIAIiIAIiIAIeJqAdANPE1b/IiACIiACIiACIiACIuAfBKQb+Md70ixFQAREQAREQAREQAREwNMEpBt4mrD6FwEREAEREAEREAEREAH/ICDdwD/ek2YpAiIgAiIgAiIgAiIgAp4mIN3A04TVvwiIgAiIgAiIgAiIgAj4BwHpBv7xnjRLERABERABERABERABEfA0AekGnias/kVABERABERABERABETAPwhIN/CP96RZioAIiIAIiIAIiIAIiICnCUg38DRh9S8CIiACIiACIiACIiAC/kFAuoF/vCfNUgREQAREQAREQAREQAQ8TUC6gacJq38REAEREAEREAEREAER8A8C0g384z1pliIgAiIgAiIgAiIgAiLgaQLSDTxNWP2LgAiIgAiIgAiIgAiIgH8QkG7gH+9JsxQBERABERABERABERABTxOQbuBpwupfBERABERABERABERABPyDgHQD/3hPmqUIiIAIiIAIiIAIiIAIeJqAdANPE1b/IiACIiACIiACIiACIuAfBKQb+Md70ixFQAREQAREQAREQAREwNMEpBt4mrD6FwEREAEREAEREAEREAH/ICDdwD/ek2YpAiIgAiIgAiIgAiIgAp4mIN3A04TVvwiIgAiIgAiIgAiIgAj4BwHpBv7xnjRLERABERABERABERABEfA0AekGnias/kVABERABERABERABETAPwhIN/CP96RZioAIiIAIiIAIiIAIiICnCUg38DRh9S8CIiACIiACIiACIiAC/kFAuoF/vCfNUgREQAREQAREQAREQAQ8TUC6gacJq38REAEREAEREAEREAER8A8C0g384z1pliIgAiIgAiIgAiIgAiLgaQLSDTxNWP2LgAiIgAiIgAiIgAiIgH8QkG7gH+9JsxQBERABERABERABERABTxOQbuBpwupfBERABERABERABERABPyDgHQD/3hPmqUIiIAIiIAIiIAIiIAIeJqAdANPE1b/IiACwRI4evRocPeuXLkSwt3gnlK9CIiACIiACIhAWAhINwgLPT0rAiIQVgIBAQHOOsD27dvLlCkT1q71vAiIgAiIgAiIwFMSkG7wlMDUXAREIPwIpE+fHt2Az5w5c6xex40bh2JAJXetShVEQAREQAREQAS8QODZhw8femEYDSECIiACLglgNMiQIQO3ihQpsmHDhrx58+7YsYPLI0eOSDdwSUyVIiACkYnAs88+y3IkjEWmd+rva5HdwN/foOYvAv5NAAWgUaNGrAHFgG+jGFAjxcC/36tmLwIiIAIi4J8EZDfwz/emWYtAJCJgmQ6sNcloYKFQQQREIHITkN0gcr9ff1yd7Ab++NY0ZxGIVAQs04FZlYwGkertajEiIAIiIAJ+RUB2A796XZqsCERSAnbTgYwGkfQla1kiIAIuCMhu4AKKqiKUgOwGEYpfg4uACDwiYJkOZDTQb4QIiIAIiIAIRCAB2Q0iEH5kG5rDqpSWPrK9VC+ux5gOZDTwInINJQIiEPEEZDeI+HegGfyXgHSD//LQVagIoBUMevThaSS8BAkShKobx4fodvPm7QsXLne8oetISuD48aNp06aPpIvTshwJVK5cpmDBgPD6c+HYu65FwE8ISDfwkxcVhaYZPQqtVUv1AAFLK7h69Srdm2SUYR9nyZLl774bePXqlTRpArJmLZM2bUCsWOGjb4R9burBcwReeslzfatnHyJw69aV48e3L1jQ7cSJ7fHjJxg/ftyrr5bxoflpKiIgAiIQhQnIbhCFX36Yl45iwPm1JiF91apVsRyEPSc9fbZr123q1HGBgeMCAqqFeY7qQAREwKcJbN8+Z9y4wDp1AgcM6CYbgk+/Kk3OMwRkN/AMV/UaegKKRQ49uyj+pKUYcJDtsmXL5syZE3bFAKTFipXZuvVojx5HpRhE8V8wLT+KEOBfOv/e+VfPv32fXXJAQAACHJ9vv/02uEmeO3fuueeeM82IvAqumZfrsej27NmzWLFi8eLFY24xYsTInTt3p06dzpw54+WZaDgREAF/ISDdwF/elG/N064YLF++HOtBuMyvfftuDx4kaNFijjyIwoWnOhEBvyDAv3f+1fNvn78APj7hyZMnBzfDWbNmPXjwILi7EVLPH+csWbKgCaxfv/769etx4sS5d+/e7t270RZy5cplTiKPkImFfdB58+aNGzfu0qVLYe9KPYiACDgQkG7gAESXTybgoBiElxsAO23Dhw/ClejJM1ALERCBSEeAf/v8BfCdHXeXgJGn//rrL5e3ZsyY4bI+oio3btz4+uuvnz9/vkiRIgsXLrxz5w7qAWYE5pkzZ06kau76r/WgS5cujRs3Du5dRBRzjSsCkYOAdIPI8R69uopq1aoRY4ArEZtS4aUYsADCDGrWHJQ4cXqvLkaDiYAI+AYB/u2/+Wa3Tz7p5hvTcTGLl19+mVqXOgAiOH8P06ZNi+uOiye9XoV9oEGDBrdv337nnXfWrFnz2muv4U3ELJhejRo11q5dmzlzZtSD3r17e31qGlAERMDXCUg38PU35GvzY1dvxYoV8ePHD1/FgGUuWza3ePFAX1uv5iMCIuA1AuXLt12/frnXhnvagWrVqsUjLnUDXFxwKKpZsyY+/U/bLe1v3ryJPfaff/4xz7LBzycU/ViPTJw48Y8//kiSJMmoUaOIgrDqTYE/4B06dKA8ZcoUh1u+f3n37l2LFZSssu/PXDMUAX8hIN3AX96Ur8yTZERMpW3btuFoMaBDVI40afL6yiI1DxEQgQgikDBhes5IiaDBnzAsUbzZsmXDrYgT+hyaGoUB3cChnkuceXr06IHN4fnnn0dMz5Qp06effnrx4kV7y/r16ydMmHDXrl1Lly7F4Yfd/T///NM0OH78eLNmzdKkSWMiiV955ZXp06fbn3VZnjlzJvWBgYHB/aHGejB27NhevXphW7B6OHXqVIsWLV566SUzVoECBb777ru///7basAfam5hOr5w4YLpnEusJX369Hn48CFYUJ/ixo1LZYoUKTp37mxpOwQ58NTo0aPxYnr//fcTJ05s2rA0BrX6p0C985zJdUE9PdBg2LBhsKJDyqVKlTLcTA/MAaWoRIkSMWPGpH3q1Klbt27t0L9pqW8REIEQCEg3CAGObjkS4P/ZP/74I3tO6AaO98J2zf9yOMQgbH3oaREQAb8nwN8BbJI+uwwj/U+bNs0+Q5xzkOkRkfHst9dTZmMbaf7zzz/fs2cP4nKGDBkOHz7ct29fxG5nFWj16tWVK1dGbShatKjxTdq0aRPemyNHjiQJUo4cOQgmpk3t2rXfffdd5GCHsaxLLBgrV67ksmLFilalQyFRokQI93wQo80tNBPGQvI+efIkEcw02Lp1K7L1G2+8gYeS/XEUAxIfoX7kyZMH+fvEiROfffZZy5YtCxcuPH/+fHI6pUuX7uzZs988+pgHeWTu3LmLFi0qWLDgmDFj0JHQdmjD0mi/f/9+e/8hl9GdOEgHlYBmb731FmWmShkglBs2bIjHFP+TQotDD0G3QSsDY8h96q4IiICdgHQDOw2Vn0CgW7dutAh3owF98r9JRRo8gb5ui0AUIMDfAWeh2XfWjVzOZBzcimbPnn3//n2XDkWffPLJ5s2bEaCxNmABOHTo0IEDBwoVKnTs2DFCaR3WhZ8POYXY5163bl3GjBlxNHr77bcvX77cvHlzdIO9e/ciYTM0asOECROGDh3q8Lh1STOe5TJr1qxWZcgFNvhZGg+SdI4A34MHD54+ffq3337DK2nx4sXkNbI/TgADkj1LQANhUdgBuItSgUqA6WDVqlV8Y3+g0sFnicmjLC1YsACtgAd37tyJ4E6oBqqOvf+Qyyg8ZCjCuEGzr776yioPGTIELKBGT0MrQN9AaTEACbqwm0dC7l93RUAEpBvod+ApCHjIaPAUM1BTERABEYg4AsiyfNhQt3x+mEtwDkVYAPDboQFb7Oypm1kjr6NLEBmMeWTbtm32pWBMYP/FCg9A0kW6LVu27Pfff2/cbPCTwRdoxIgRPDV48GD7s/YyLvjmku1ze30I5V9++WXfvn1JkyZldx/x2rSsUKHC8OHDKXOqA8qP9Xj06NHJ5YpfEDVMCdXF3EJMxzZiKlu1akUBBcPcsr4xFGCI4Clq8NH6+eefMVywr4++YbUJRQFTCf5RPDhp0qRy5cqZHlKmTImFh2yt6CEwD0W3ekQEoiYB6QZR872HZtXG0I/919kZNDTd6RkREAER8EMCDhHJITgUIe/irI9sio+QfaEI3/gOUePgPcUmt70Z2/ZcogyQeBRx3/qUL1+eekKNb9y4YW9vlY0/EpfuBzRzfiXtWZr1rOmtevXqeOywRjyOrP6ZP2K3dWmUBPQKtCar0t7AqqSlQ0gG2//4BdHg999/t5qFokD4AXoIbl24RVmgKICIHE10iDoXim71iAhETQLSDaLmew/NqgkJ4LHwOuYsNDPQMyIgAiIQ0QSMdGsdghaCQxGO+0wW/3jnKZtK9rPttxzkaTxzuIsfP7719k+yZMnMU7gb2R+3yjgCvfDCC1xiCrAqnQsklsBMwTEI3ApuqtGiRcuePTsNHKbq3FusWLGcKx1q6IoOHSrZb6ImjCcVGFZM0g7KlPv370//wbFymIwuRUAEIBBdFETATQLswdBSuoGbuNRMBEQgUhJAwGWDnH10PNopB+dQxNpDCBc2TjUO5yhbYcGGm0kQVKlSJeOo4wyTxEfOldTg80OuHkwBxP4GF46MLaJdu3bMkOAHHnnaqbocN3SVLlE8bVeGVfLkyY2VwPlxs0znetWIgAg4E5Bu4MxENa4JOJi/XTdSrQiIgAhEdgL43uDEglbApn5wGYpgQMAu3y43702laRAcLTxkyG5EnG69evWCaxNcPe5J6AZkBOrYsSPePs7NZs2ahT6AeaF48eLcDW6qaC8ET1sNnPt5qhq0KTp0MB0YbyUryMFlh088vxlWPIhDFDEPLntQpQiIgPsEHK177j+pliIgAiIgAiIQBQkYtyLOGQjBoQgsiN1s7aNFkKTITgkHHmJ/qSHO2F7vUDZ3nU8zoIagLyvi1uEpc/nee+8hLmPsRa+4deuWQxviB77++msqOTEAxxsKxiBMz9euXbM35mABkhcxnPH8sd8KRZngbGNmsZ4l2JohuLSjYA4OaYUcnrIetwr58uUj8JoYDIfwbvIvYTFg/iZ4w2qvggiIQAgEpBuEAEe3XBCQT5ELKKoSARGISgRwJSLmFaG/X79+rNshvtYigd8/BwhwSTyxceunzDZ8lSpVOBCtdOnSJCayGjsXyA2K4E7iIBIBGZdO2vz6668YK/AIqlu3rvMjVg3e/0REoJksWbKEFEkkSjJZTYnNnTp1KrHROOizy86hbOYRcgexKDKloi2Y2APqFy5cyNlkFNq0aYOfktV5WApNmzYlN5FxYcJiQEw2qkv+/Pmt/7Mgx3O3e/fupg35kbp06RJcpLJ18AIGECbJxIhsxpJjZohW06RJE3LIgtHqPyyT17MiEEUISDeIIi86HJZp/c8pHPpSFyIgAiLgzwTq1KnD9HGSYXve+cgza2UoD5z2xe44bcjJw6HIiODkzOEQtPHjx1vNXBbI6oMcTxACiUTxpOcwL7yDEKYReRs0aIDU6/Ipq7JkyZJsySNq45iE9sK5abFjx+bQYpQK9tfpHK2D+Zj2JE4l3SfKDJ5IzJOxCHJ4/fXXGQsPfs5us7oNS4FDGxDi33zzTZYDN45OQ78itJrEoybqgM45bY1vlBbcnFCf+MbE4TwBc94Z6+JoOeP1xDHMTBXF5tVXX6V/csWmSpUKFyPsCZgdTHB2WCavZ0Ug6hCQbhB13nVYV7pjx46wdqHnRUAERCBSELBsBRQsudZ5ZezNcxYYBwSTyZQkmxzrhjjOKcJsZpvTu5wfsdcQSUyCOEIO2PnmPDJykuKnxLkH6BUhDGr1gHCPGvDFF1/gEYSOwQ4932zSU8NJag5b6Ujq/JHHRoHrP2OR2AezBkcrcNRxcEHP1kBuFtAHtmzZUr9+fUKH0ZeQ4DEj4AWEvmT18OWXXw4YMICDmTkDbv369agT8+bN4wi5rl27Gn3MtCTDErfIboTxAcchKpkkp6pxBBvKGDtZLBytA7sHJ6xRY/WvggiIwBMJPGvMdk9spwZRnAD/S2OjCzO6yWQa7jT4Q79lC+bgbuHeszoUARHwIwLz53fD0YY/CH40Z031iQRIZUFEAXYA5bRwZmXUPAljzmRUE1EEZDeIKPJ+Nq5RCcIlHM3PVq7pioAIiIAIiIAIiECUIRA+0UVRBlfUXajZ7HGwQXsNx8WLRzt1yuByuGefjZYsWeaAgGqvvdYxVqyghBt+9+nfv8zBgyuaN5/NKrww+cgN0xngwYPL+/cvmyZN3i++2O581zs1CxZ8yXY4Y2XNWqZ9+6ADaB0+Q4dW27GDkFMv/Q6Y0ZkSEytfvk2tWoMc5mNdjhsXuG7dj40ajS1ePNCqVEEEREAERCASE5DdIBK/3HBbGr6bJml0ROkG1kpefDFuzJjx7T8c2nP27MFFi/p8803Ba9fOWi1VeCIBwXwiovBqsGHDJNPVH3+suHIl6Kxc3/zs2DFv7dpxN29e8s3paVYiIAIiIAJeICC7gRcg+/0QgwYNImVeo0aN0qdPH7GL6dJlZ+LE/5nD3bs3V60aOXNm+wsXDv/881d1634fsTMMxehly7bCYpA6de5QPBuWRyIlTGcgSZNmrlVrYJw4Lo5/cm7siZojRzacO/cHLsVx4iS5fv38pk1TK1Ro74mBnrbPXLleixUrQdq0+awH583rcuLEjs6dt8WOnciqVEEEREAERCBKEfAVuwF51vh/ZyiilMgSjcxKLmeyL69evTpKvTzvLBajAboBY/lmdGCMGLFfffXjYsUaMcMdO+Z7h0n4jpI/f43y5dsmTfo4mWD4dv5UvUUCmM7rTZgwDXiLFKnvfMs7NcZokC1buSJFGjLixo2TvTPuE0fJmLEoZLJmLf3ElmogAmEkgM2ZWNtQ/C8+jOPqcREQgVAQ8BXdIBRTN4/079+fbG4cw16sWDHyN4e6Hz0YHAHfMRoEN0Pqs2QpxffVq6dDaOPRWw8e/HPr1hWMGNYoFy8es8ohF06d2o1P/I0bF0Ju5rW7EQ4zfFd69+4N8B47tjl8u3WztwcP7m/ePJXGRYo0KFCgJoW//tp65sx+Nx8Pl2b379/ll5Nv0xtTMn5Nly+fgMy5c4eoN234NaZ858512puy8wSUTcWZiWpEQAREIDIR8HufIlJH8z5GjBiB9SAyvRgfWQvpiXzZaGBRevjwAeU4cRJbNRT+/vv2778PWb9+/JkzB5CHkiXLUqhQnYoVP3nxxXj2ZkhIP//89a5dC65cOcXGeaZMJWiTI0cF08ZEsrK32r79cvtTS5cOmj79YyuO8+TJXd2758ubt2rTptNxcFq7diyuLCb49fTpvb/88s2+fUuuXz9H5HTKlDlLlGhcrlybaNGeMx3OmdPZikMdO7YRE0aOfO+9Cfbh0Bw6dEjJKjp12pQuXVCuboTdX3/ttX//77duXY4RIw4CPdPOlq2s/anQlV3CRCLcunXmsmXfHT268e+/78SLl/zll0me/rmDuYN5/vZb3+3b554//yezJTIkY8ZiuNDkyPGqfTK7d/+yZMmgw4fXok09//yL6dMXZvJ58rxlb3P8+LZffulx4MCymzcvvvBCrPTpC5Up09KI16aZCao2zEEB80uXjj333POZM5esXr0nfZpmyL4OscidOqVH9h006Apb+IsX9+fdMdVUqV6uVOlTyNvnQCgLAbt79iykfeLE6UqWbELI++TJLZj2++8/DiGwt3cu7927GD8i1pg//9sxYsRNmDDt5cvHGbdKla+cG9trEM1XrhyxcuVwfn9YFL+B1av3IhLg99+/LVnyfTurrVt/WrZsyNGjm+7duxU7dmJ+B5hkunT/Hri7YsUwfldxrMJCNXFiU6ZUtmxL4o95odbvsGljJtCvX5CmjWdR2rQB1pQOH143d27nQ4fWoEVgiilatOEbb3RhXaaBCVnmEV7BggVfnTixEzswdglGeeml/Js2TVm4sCcL4VcLFybWnjv3G1bPKoiACIiACPgUAb+3G+BTBNB06dL5FNbIMRkUAwzBRBpwFn2ERxqEjHTfvqU0yJChqNUMKapPn5KzZn126tSeRInSJkmSAZ9vdABCllEGrGYIoMj0RCwg1HKS5rPPPrd372+DBlVctKi31eapCqNH11++/PtEiV7KkCFINkWiYkRkwdu3r9I/2gtWghkz2k+e3Nxlt8b1hZBQa5fXNNuK9ZedAAAfqklEQVS8eTryK8l2jGKwZs2Ynj2LIBT+88/fKVPmoA3S9oAB5UI9bftknGGiGIwf//7IkbX++GMlEcwpUmS/ceMisvjXX+dFObGeZTf6m28KEBd+7tzBhAlTo4yhnu3Z8+ugQRW2b59jNVu6dPCQIW/s27c4WrToMEHwpdvvv69iBezSEqf8Rwucee/eTYaLHv0FUjkxgUmTnLk9pH7+/K4xY8ZLl64Qb5Ap9etXBs7WiC4LS5YM5GWheKBFIFKjIYwZ0xCwVmNmxe8Gci26EHO4efPy3LlfjBhRc/fuhbt2/Ww1C7mwYcNEGuTNWwWNFHHZ6DZPdCtCMRg+/J0pU1oyq3jxUiRIkHrPnkW9exdjMqiR6F3WoFOnfjRiRA3ggIhJgguJv1evInaYpjHqzYABZdG10qTJkyxZVqsHU0BlxTHPZPpC8aBsDzngt6tfv9J//bUtQ4YiKAb8C0LWnzixmUMnKDMkXMLsgGbCy/3jj1UDB5b/6acOo0bV4/efZ194ITZmk2HDqvOv0uFZXYqArxC4csVXZqJ5iEAEEfBju8E9dslu3bp//z7obty4gVs8PkVEHbhD8ubNm5zLyOnxHBRPew6b5JtLd56NIm0sxQCDjDEd+MLCb9++hohjnwmb8atX/4DMhOxVvXoP6xabu0ghSNJNmkxGSKWePeAxYxqwvTpqVN0OHYLMTffv30OsRCsoWLBW/frDEYzY10RPQACdPbsT8cHJk2ezOnSnsH//kpgxExDjyya0aT9rVkfk4+LFG9euPRipmkqk/B9+qL1q1Q9vvtkVmc+h2+zZyyMLXrt2ZteuX/Llq27d3bgxaJeaDWO+2ZSdNOlDCvRZunRzZGsWsmrViGnT2jLcSy8VcNiktzpxKLgPk87RBAilBaaxqKB6zZz5CZUjRrzz9dd/cIvOsRhcuvQXG8Pk4mSXnZo7d64xK5otXz7UZGhlx3327P9xq379YSVLfoDxhMnPmvUpCgP5NI1qhDsWqghqD1Ha1ar1gBuy8vr1E9jzZh+dHXTsP9ZaEJoJqP3f/zYYQwG5qsgJi9MOhOFjNXMo4Gg0e3bHRo3G8Gq4xRzGjn138+Zpv/8+uESJ96ihAb8n/I159O4G8dvFfFAn0Da5iz3EoUOXl3SCKM+twoUfRzugGyxZMgDhHvOLZdlwfhbjAA9CFTOUsQWdPXtg+PAaq1ePsjd+ZMkZwi8AMIsVCwSmwYsZYcKEJpkyFUclttovXtyPETt23GAX+q27OXNW5OfrrwMwQ7Gvb7cY0GbLlhn8pmF5iB49Bv9G4MDbR+2pW3eI3QrHv53GjX8sWvRdHuE3Ac2K35PffutHh5iYMJphQunZszAGH1A/0XJizU0FEfAqgW7dnkE94Dt9eq+Oq8FEwGcI+KjdAMGUPbZq1ardvn27c+fOnC3PJQHHODHs3v14O3Dy5MkcI79mzRpgvvXWW5StWOR169bxrIlvjh8//jvvvMMB9XbmnNlOe85aX7p0ac6cOTnW/s8/H2/FoTZ07949R44cHMAeLVo0Drrv3bu3sU6YHtyZmzUW03vjjTfQOph/ypQpP/jgA854t+5SYEd24sSJJUqU4Ch72nBYfevWrTkr3t7G+2UylhqLAYqByV7q/Tm4HJGN6o8/Tmj/6dIlG8IHokzHjuvY+zRP4UaC8IHU8tFHC41iQD1b1Fwi1R06tNp4n2/ZMp2WNHjvvYlmxxTxpVSpD3F4QADCC8jlHEKoRDJDSrMUA1qeObOP71de+cAoBpTRQ5CTcEa6d++2c1eId4UL16We+Vt3L1w48uefaxHLTDArIjhyKn4j5cp9hFxIM/aMy5ZtXblyJ8o4O1kPhlxwEya/ovj20JWlGFBGvnz33dFZsryCqkbWSzMQW8WPXF96GMWASl5BmTItKKDCmTb4nKAs4YvyyitNjVcVk2ctAMmd+3XTBsMLQjld1a79reFGS/Lrv/HGFzRAxjXNzDcGFpJTWXI2zk5g4RauO/ZmDmWUDSZgFANuMQdUNQqXLj1+in13fMww1DRs+IMRf0GN01GhQkFvx80PvlX8SsDq5Zcrm0ce7bunpRyC6YDfPbNG9FXLSQw1tVmzGfyJsA+NiYbLypX/V6LE+wYmTnF16nybPXs5bB1gtDdmyR98MNWlYmBv5rLMr3SdOkP4DeQu/0ZwEkNvYZ6I/vb2WBuMYkAlpjOsJRRw0uPF8RTluHGTFi5cjwJKI9/6iIAvEiD3xvbtmKGfCQx85uhRX5yh5iQCHibgo7qBWfU///xTna3gHj2SJElSsGBBAo4XLlyIGH3ixAkaZM6cGck1efLklCtVqkQ5RYoUlEeOHFmyZMm5c+fSHhEfw8KsWbOKFClCvenW+kaXqFy58sWLF4sWLYp6QD1l+v/iiy/279+PQpI2bdq9e/d27NiRBtyyHqQQ8txMyx9++KFUqVK//PIL1owsWbLQw6hRo3Lnzo12YRogdTHthg0brl27Fh0mW7ZsZ86c+e67715++eVNmzbZh/NamTwSAQEBjRs3NklLfUoxAAKSov1wA8pGJML1Ytu2WRYl/Fgo58xZAWkV4dX6weHEBNpiPaAB7kN842JuJGzr8XffHYXndEDAv9v21q2QCwhPOXNWsrdJkSLI4QfvC7Z4caswt6pW7Y4fNke22VtaZePyTvwDMrSpNHIkW85skFODTwvfWBWsdZmCEUDN0qzeQii4CfP06T3I2cjceOzYR2Q5uXO/Sf/Hjj3+Xa1Rox9RGWTGtAYlOpz9fuuSAiIjwQNIrsOGvY0nDBv2VGIqAQg/puWBA0F+SlgVHERh3P2pxxxkkeQS5gEBVc2D5jt+/JQU+Odvr3QuFyxY215pnkLeNZV79y6igEJifsGsliYjlnUZcsE4FBUoUMv6BWNFxq1o06ZpCOsuHz95cjdqCcqq3XBES1yGUC2sRxCvjYqLkmNVmoIBhfuQvZ7Aj7hxk9lr3C+j0DpwQAlxfhxLhb3SWFeyZStjr0Q9sF+qLAK+SGDOnGfix3/mxx+lIfji29GcPE8guueHCP0IixYtSpo06bZt2/LmzUsvR48efeWVV1AMsBh8+umnKAB82N4+e/Ys4jsF2mzdurVFixZ4Cn3//fdNmjRBKMfy0Ldv365du1KPhmC6MnPq0KFDp06d0ASMZxGV7Ovv2LGDUcaMGYPuQQ2jN2jQgMoPP/xwxowZ5kG+Q54bDfbs2dOyZUsKQ4YMad4cx4/nkLaZ0syZM5s2bbpx40Zza8KECdgKSLVUrlw5ak6fPt2qVSuUGWwdBw4cwJhApXc+aAVkKV2xYgXDEb+BHxG2F+8M7f4ozin5kTLxZJg2rQ2+4Mj9RvTHaYE+ccfnx2XnZtvy/PnD3E2VKqdDG0RVfhwq3blE9mIH2t6yXr2huC2huuCnjlzI7i/bqNgl+HFoaT1F7CZSIF4xuBXlz/8O9XaHItxUcJGnskePQtYj9oL7O7Juwrxw4Sj946uDucY+kFXGN8kqP7LYTD16dDOvgBMncD23bpkCYdONG4/HOwifGX6AkCZNACYC9piJITZtTECIiaOwP474jriJYoDobORO7qK0oAHam7lZdnbosj+IrYZLo9rZ67E+2S9DKGMqIaaCBgQn4KtjtcRphzJuY8juLr2/Ll40Q2cze+3WgxSIEzh8eL2pAQKbCyh4zgsx07bH1fAIcQL2rp6qTAi1O+1dvgiXle70pjYiEGEE8CYaN+6Z6o+2h9AQ+CHZSTd5GUXYC9HAXiYQmv+nem2KhASw0W5J84TDIrsj5YfgctOnTx929BH3EeXNPBGvu3TpwiPkMkJhsFsPChQogDRsLWffvn2zZ89OlCjRnDlz+Db1+fLlY+M/a9asP/30E2pJmjSP///6xLmRXJU2TANZ33SFZQBLwrx587AJXLp0CZenXr16cWvSpEmlS5c2bfA7mjZtWkBAAKoFk6lXr56p9+g3SldgYKDRCpgkWgGXHh0xHDvHOwUfkp075+MCRBCq0Q1wuWEIHCHs2Vrsg5pAgocPgzZuMSbYb7lZNhveDo1xQnOoSZUqV9euuwjKZB/6wIHlhD4j9K9ZMxoR8+OPlwQncpEEZs6cz3HyRjfgkdOn92FkyJIl6JfELI0C5gWHrVyHoUNxGQJMfEiCyy2DJmPGwrkLJ362wzmfjrRChLQybYR4Yk/tk2FR2BYw2vBz6NAqNr9xvsdRCvWgWbOZ9i12+1OmbJZs7e5T6WBbcH4kuJqQH7Q4OzzuPnPCqY1lAKuLSwcnzEEudYPghmYmrkb/j5eRma0zJeqdNQ2HpUXOy/96YT1e47JlzzzaS/rPksPY8uHD//TGxfLlz5Qt61jJdVha8j+sL7907JP/fTCWwyeMLbt2DRKFHT5Ae7R59J9q91t6Artzn+GFna2xNm2eGTz48WItDQGdQR8RiOwEovvyAvHzwVnIPkPj+WOvcSj/9luQlwieSIQm22+99tpr6AZYFeyVb7/9tv1y8eKgTT5GRMKzP464jIawYcMGfIEs3eCJc/v11yC3FgchG30AEwTRC2gsBE5gJcBtCeXHPhxPMVt0A2brHd0AOY55oiEcO3YM4wZ+RNQYO4ydjy+XiTdAN7hx47yZpJG5EU8JNg1h2mbDlfxFDm04GpY9XfQHy03coQGXLqU952bUIJOxL84PZTQKst9MndoaDWHevK7BTQ+fbHQD41ZkEs7gJWJkWVxNcOfAi71atW/wz3E5YhgrHWCS5YkO2Z8ODBwXQs8kKUIxYCeb8FlyZVqS9/Hj252fYgk4zBifGewAZDGaMqUV2ZmIKcdhnfeCmQKNyH5kL51QaRzcjf+Pc7fhWMOvELl0eE25cv3nTxAxwW6OYl4cPkjO3AhoJlQAoxbRKcaJ396n+e0ldB4VyEGgt48OBCBjJsKAkCBBKnsPZAvl0qHS3iAKlf9/2+U/S06Q4D+X5iKMLZ17ZBSXfYalJfvZzn0G/GuV+rfvMLbkcedPcAO52dIT2J37DEfsDhoX5P1n18z5nahGBNwn4NO6AeHCzhuxIawNufby5SB7vWVqcGhs7lqVbNJbZQpHjhzhe8qjj73eKtsfD3lu5FBC7ufB7Nkfb6lanVg1Zrjjx4/TlXXXXrAPZ6/3RBndgA9aAYYUDAhly5bFlIH9BGXGE8OFe59m799ybiEWkyGQrfHfMEHGZkQkSwJwcXQhnIAULhxVi3zGeQIVKrSzez4sXNiDbEJEDFu6gYNvDI5M9qScwS2HhEKkimczvmfPv4wHEd9sFRPKOWHCByRyCe5B9t1xPfrzzzU7dy5AXGZudjd3po2dBD9+ZmjvgQytZOvHjb5BgxH2+qctO8BEVYDho3joNczK3tvgwZWOHNlAlCqGDiRptsmxIRh/equZXZylkoRFc+Z0wrzTsuU80wbDAqvD/QZh2jAhWRNBBbiKEfhr6Rg0poZvFIbQBdSa4dz8JliFqJV1634sV661XUCnxp0eUDgxhtDSRI84PMK60A0Q63m/xm3M3gBjF8D5XUVZMsmdzF20BVLiWi3hRhouwkvIIvXWW19a9RQMKDDaK6No2UG8C4FCuLdEknazT/dbIpu6KZ56oiVBum5+3G/pJiLGdbOl+zBDbtm27TM7djxeLloBVhRnW5ObNNRMBPyNgE/rBk8LEx8e8wgBvi6fdZB0Hbz5zePoFbj0uHz8/9o729gqqjSOh83auKRCAwbiS1IoWY2rG1oNuJA1QNrKrgFa4INBzVKBFRMMvQiCFDTlZT/Al5aGwCe2rQmSEjHi9oObldcgkkWkkGgUzKaoJLubmtDaGDeasL/bZ52d3nvb3t4705m58zcEp3PPnPOc35lenuec54U9/oz302/i12Q3h8mpasMRS80pQXoP3Jk1K7NDecbGntwcMBDq8CkyC4Gjg9OnT6dA82Qgnzpxsqbgso9i9NlnJ6hUgHe7ea6j3ba3P48TNpaD5XacM+cP6NMotW1tz5PdBYWMbe/z5/+MMw/qoGWkKS5Ohk6iqmJFmBqHx/8bb6xJcebOOKOpU3+JusxuNzk6a2r+ZOGbaI0k4qQ9QmZ8ym6ibWMbHDu2mV1hFER3/MOTT76CbfDuu6/TIZkl2Xim9AE6K3PBHcXSgA7Tc5YfOTCxTLCdCOcgdT0V2Qi2Rl9ns587OAWhplsdLtulJjsnPkJWhIFtb/xqrCKBE1dNcn2exQWfOF2OR0ztZqUIrkAwY0JqI4qsEanc0bHeyWH64YdtTJA2Cxe+kuUU8mk2d+6q997bg0MXa/300//PYWqnASP2bM1gYmZqSnvMLQspwfBLtw0AzhJjQWFAYgC4c5jyfrq7qq7eRD5cSg1wgmQ5TDFieRDnOixSMsC6G2d/nX3ISvZ9qqUIRIkAscjmTSSrIErLJlk9I1BQtsHkyZNR9wk+JrXRvfcOOmTPBpip/rNnz3bHJGTzYHobxOA0gI3/69evp1gaxCITt7BkyRIbDt8kduvTewjwTiKRwEjAMMD9KSrmwcSJydDhL7+8hNOO7dCTZ51quOipjY2/spSapKdEW7377rKVK1sNL3GxL7zQsX//IvRU8pmyW0/8KKl4+LS2djehAlzw9wMPzKc6MhWm8DIiywqnAT/++P3ixY1UzLV+hvr7jjt+QZ4tqlORvJ+6swyN6obvDe1RDUncOdSD3Gf3Hc3Ygqot7YzTmMyhy5btwS+ForYo6Cigvb3/NH2ODEgWceE0zuEiHSaisj/NNnZLy+8JPMAeQDBQM0HSYlr2JKI7CEhA6SeBPak/77xzAvlbyWfPxjmx1Ox5UwYLRZ+A44qKZSSVotDYm2+uo0RaX9+/LbqaE4+HH07m+mQh8Lai4AAWAhn9J00q/fbbf9m6oO+OKotoDtO3R5gUOUN5NyjOgAaPDORcAjJaO6ERI3Zr4eOO8ZPeno+w7jg3wFLCAEhpQLJUXl0oUc+O9YUzRhfvj6FzGpM+iIS8VDPAgKHgwF13TR1IEfs9MRsApL3TMssLArtpSWEHyl2TvNXCcrJ8Vs1EoEAIdHcnD2dkFRTIcmoauRD4WS4PhfUZtjPRZZHu6NGjKTKuX7+e/W+CklPuu3/EkYYfiTymkpr7Pl74pEsij2pfX5/7/vDXlneIBETuZhRrW7Vq1YYNG7ioqKggkgHj4fLly+42nDlwYoC0Fjvh/mjMrhmdEwOOUMw8SAmHGDMxsh/IfF3Yoac+rj2Fz3pDw8WnntqOfsMeP84qqDtkgt++/WO3mz6a9LZtH+PTwqEB+usPP/yHwIB16/5itQKsK7xfKisTqE24x7CRjHa7efMHPEJGfHe+zozSUnaA+FqsCzaDcV5HQjbO8QDZuvXvwzvG8KkpyqSXSR8F3fHll0+ii7PvjtiEN9ImkfhbipdRRpFGvJkOE+FffPFtlMWyst9g3jDi+PGTIPDaa11WCs36RJlGMMgTY4Atcd99v37ppU6OGjAt0Fa/+OIDc81as+bI8uV7sR8o4ktQAYYWq4DBRv0Ex4OI6maUM8NAopIu2LFDYAhJ/JdGlN+rBkjV0PDRQPrOn3Paw2uD5JYwlLdlmFHwsyJfEw0yOhTZg9gGXFCcwZ171+mTYGLCNlas2M+RFzYJJithGK++eqGoKJm4zD065132goEIUOACGuhys6AoRED4OEdVrKAFUjsi6UIE4kKAQwP+4MI0oE7EZdaapwi4CIxLOaR2fTSmlyijRAucOnXKlHuiflGdyaRJgKxbDtxdUKzr6+u5sPu0xz/eefDkyZOVlZWULWtpaVm9ejUXuP4fOHBg48aNhC6g6VLpjAfJzkkBBBIBpaTpxMn+7NmzpEZtbW21HKYUOqD+AKXTCAsmoRDPZikbJQvoB10HSchWRA5Tqi+TZ8nSEJk9QM6lnTt3ksO0vb0dsem8p6eHzKoWDUwO06KiIptmIH9jEoAXaBgJTk0GnyTBi+nSJWrYNfrUv7oVAU8IEPLe3FyN2bBp0xlPOhxVJ3v3/hZPM8xCpybaqB6PRGOO4x57DO/uxkhIKyFFIH8CticSEmUs/+mohwIgUFDnBqwHu/W7du3ClZ+SAuz0U00MRyPMCX7rSGBqhsEwy0a1genTp587d45SZWVlZZQ/4xEMAwqWUaZgmAfTP5o7dy4pSinARA5TZEAS5MEwwIno0KFD1p6SzwQb3Lx5s6qqisADMqXiCoVhwHkCtRSCNQyQ0E4PsNAwD8Lm+JQOXHdEwEMCFHteu3ZcU1NVSp9WVo8UWCn3vf2xoWEao+Mv5O62v78HRyPOcAhXcN/XtQiIQNQJOHnMoz4RyV8YBArNNmBVULjJRkoqUvTya9eusWFfU1ODuk/FsRHXDGOAmNOtW7fOmDEDVyK0dtIKsbV/4cIFp+LBiJ04DSjQhl9QdXU1tgqSoGpzBEH/jz76vyBUjjU6OzsPHjxI1Wc26fEvmjJlytq1a69evcodp58AL5DZNvC0jRfgKmjosSfw0EOVOPaQypaC1s7oVKQmBIIfcXlybvpxYdW1yWNrURYMQagDkfT4ID3yyO/cPkV+jK4+RUAEREAE4kwgLD5FcV6D8M+dcgdYSvhZEaPsk7TYHvIp8omtus2NQGfnTgtfIUSEuF7yXFH4gq6eeOKPzz2XzKbq3394/BPSTdg6Id0zZswhqmQgWqOPqOUtW87fc09qJW//JBn7nuVTNPbMNWKABHCcxluBcwNi/AIUQ0OLgJtAAZ4buKena08I2KGB3Io8galOokJg0aLXiQ8i9JzYa8pZ9PT8Ay9/wpGffTav8hHZTJ/cRNu2fUSCWoyBTz75K7lii4snE9dOje3CNgyygaM2IlBIBFKCKgtpappLdAkUVA7T6C5DyCXnuADzgJhvIpLLhyj+EPIpSDwRyIEASYr4k8OD+T9CRYtnnjnAn/y7Ug8iIAIhJ4D7bsgllHixIqBzg1gtd+6TNW8iKiXn3oWeFAEREAEREAERcBGwHIDadHMh0WXwBGQbBL8GkZDAyS0bCWklpAiIgAiIgAiEn4D5FMk2CP9KxUpC2QaxWu7cJ2u2gYKlcieoJ0VABERABERgMAE7NyDhx+Db+kkEgiQg2yBI+pEbm/p0kZNZAouACIiACIhAOAnIpyic6xJzqWQbxPwFGMX0VZxlFLDUVAREQAREQASGJYBDETtuM2fOHLaVPhSBsSYg22CsiUd9PGq0RX0Kkl8EREAEREAEAidg6T3MZTdwYSSACDgEZBs4KHSRFQE7AM2qqRqJgAiIgAiIgAgMQcBC+Gpra4f4XLdFIBgCsg2C4R7FURUsFcVVk8wiIAIiIAIhJMAh/PHjxydOnKhzgxCuTsxFkm0Q8xdgFNM320BFHEeBTE1FQAREQAREIBMBORRloqJ7oSAg2yAUyxAJIcw2kE9RJBZLQoqACIiACISZQGNjI+IlEokwCynZ4klAtkE81z2XWavEQS7U9IwIiIAIiIAIDCZApMGNGzdKS0vlUDQYjH4KBQHZBqFYhkgIwbkBnpFXrlyRW1Ek1ktCioAIiIAIhJOAHRrY3+GUUFLFmYBsgziv/qjnbqef+jobNTg9IAIiIAIiIAIDBIg0OHPmDHttylCkNyKcBGQbhHNdQioVtgFfZ+3t7Z4fHXCueu3a6ZBOW2KJgAiMFQG+B+RlMVawNU4ABEhPZLtsbW1tJSUlAUigIUVgJAKyDUYipM9dBPgisy81z48OysvLv/qqyzWULkVABOJIgO8Bvg3iOHPNOR4EmpubiTSYN2+eDg3iseCRnKVsg0guW4BCYxvY0YG3CYuwOiZMKPnmm+4Ap6ahRUAEgiXANwDfA9pMDXYVNLp/BDgr2LFjB/1z4d8o6lkE8iQg2yBPgLF73Dk64NzfW/Ng8eLaEyeaYwdUExYBEfiJQEdHgu+Bn37S/0WgoAjwL6YdvLe2tqqWaEEtbcFNZtzt27cLblKakO8E6urqiDrgAIFEbF45AOCF+eCD5cuXN5eXSznwfQU1gAiEjUBX1zvHjiU+/7xL5wZhWxrJkz8BDAM21Hp7e+vr63Eryr9D9SAC/hHQuYF/bAu5Z85DV65cydech6cHKASHD7e1t9fJs6iQXx3NTQQyEeC3nt/9w4cVnZmJju5FnACbaGYY8O+mDIOIL2YsxJdtEItl9mOSjnlQUVHBMQK7/vmPUlU1v6GhcffucnYQ8+9NPYiACESCwPnzbfzW87vPN0AkBJaQIpA9AYyBBQsWsJWGYaAwg+y5qWWABORTFCD8Qhga78l9+/YxE/yLuOa//P0BLl7sWrGirrh4WlVV4v77y8ePLykEUpqDCIjAYALffXfr66+73n+/ub+/+8iRtlmzygd/rp9EINoELMCAUgZMo6mpiX8foz0fSR8bArINYrPUvk2UWgekNCX8gBE8jEDYs6f5rbfe+fTTruJizI1pvomvjkVABAIgcOtWd3//rccfn79w4fwtW6QzBbAEGtJXAhQ4W7p0KUOUlpZyXIBPka/DqXMR8JCAbAMPYca6K7MQ+BvHSm9B0Cf/edunehMBEQiWAHlalKol2CXQ6L4SwM+WN5yzAs/LAfkqtjoXAQjINtBrIAIiIAIiIAIiIAIiIAIikCSgWGS9ByIgAiIgAiIgAiIgAiIgAkkCsg30HoiACIiACIiACIiACIiACCQJyDbQeyACIiACIiACIiACIiACIpAkINtA74EIiIAIiIAIiIAIiIAIiECSgGwDvQciIAIiIAIiIAIiIAIiIAJJArIN9B6IgAiIgAiIgAiIgAiIgAgkCcg20HsgAiIgAiIgAiIgAiIgAiKQJCDbQO+BCIiACIiACIiACIiACIhAksB/Acm637znL7iAAAAAAElFTkSuQmCC"
    }
   },
   "cell_type": "markdown",
   "id": "b21655de-1c08-4ec2-b69e-9f34832a5692",
   "metadata": {},
   "source": [
    "![image.png](attachment:019fd573-4b5b-4076-8dde-679d30cb9121.png) "
   ]
  },
  {
   "cell_type": "raw",
   "id": "fdd414ea-a4dc-4207-aa56-3e2241529c31",
   "metadata": {
    "tags": []
   },
   "source": [
    "!pip install git+https://github.com/lamm-mit/PRefLexOR.git --quiet"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a92b8a4d-1631-4d48-9495-6a7403795ad1",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "#os.environ[\"CUDA_VISIBLE_DEVICES\"] = \"0\"\n",
    "\n",
    "from tqdm.notebook import tqdm\n",
    "import openai\n",
    "import matplotlib.pyplot as plt\n",
    "from datetime import datetime\n",
    "import datasets\n",
    "import multiprocessing\n",
    "from accelerate import PartialState\n",
    "from trl import ModelConfig, DPOConfig, DPOTrainer, ORPOConfig\n",
    "from transformers import (\n",
    "    TrainingArguments,\n",
    "    AutoModelForCausalLM,\n",
    "    AutoTokenizer,\n",
    "    PreTrainedModel,\n",
    "    PreTrainedTokenizerBase,\n",
    "    Trainer,\n",
    "    TrainerCallback,\n",
    "    AutoConfig,\n",
    "    BitsAndBytesConfig,\n",
    "    DataCollator,\n",
    "    is_wandb_available\n",
    ")\n",
    "import torch\n",
    "from peft import prepare_model_for_kbit_training, LoraConfig, get_peft_model\n",
    "from typing import Any, Callable, Dict, List, Literal, Optional, Tuple, Union\n",
    "import inspect\n",
    "import random\n",
    "import warnings\n",
    "from collections import defaultdict\n",
    "from contextlib import contextmanager, nullcontext\n",
    "from copy import deepcopy\n",
    "from functools import partial, wraps\n",
    "\n",
    "from llama_index.core import (\n",
    "    VectorStoreIndex, Document, SimpleDirectoryReader, Settings\n",
    ")\n",
    "from llama_index.embeddings.huggingface import HuggingFaceEmbedding\n",
    "from llama_index.llms.openai import OpenAI\n",
    "from llama_index.core.node_parser import SentenceSplitter\n",
    "from llama_index.core.extractors import TitleExtractor\n",
    "from llama_index.core.ingestion import IngestionPipeline, IngestionCache\n",
    "from llama_index.core.indices.vector_store.retrievers import VectorIndexRetriever\n",
    "\n",
    "from datasets import load_dataset, concatenate_datasets, Dataset\n",
    "\n",
    "# Custom imports\n",
    "from utils import *\n",
    "from active_trainer import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c1ef9537-26a2-4093-9f1f-f13b563a8618",
   "metadata": {},
   "outputs": [],
   "source": [
    "#Set HF token if not already set\n",
    "token = 'hf_.....'\n",
    "from huggingface_hub import login\n",
    "login(token=token)\n",
    "\n",
    "#If you want to use OpenAI as inference engine (e.g. in Llama Index, or elsewhere), set these secrets\n",
    "'''\n",
    "openai_api_key = \"sk-.....\"\n",
    "openai.api_key=openai_api_key\n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5adf1720-9d40-4fad-8bcd-f947b40e0296",
   "metadata": {},
   "outputs": [],
   "source": [
    "think_start = '<|thinking|>'\n",
    "think_end = '<|/thinking|>'\n",
    "\n",
    "#raw dataset used, data to be expected in 'text' field\n",
    "raw_data= \"lamm-mit/....\"\n",
    "\n",
    "#whether or not to use LoRA to create a trainable model \n",
    "use_LoRA =True\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "61e01145-c084-4dd8-a91e-14f4a589101d",
   "metadata": {},
   "source": [
    "### Start server to serve LLM, e.g. vLLM or Mistral.RS"
   ]
  },
  {
   "cell_type": "raw",
   "id": "25e16641-c332-4b1e-a6a7-3d4c79e1564e",
   "metadata": {},
   "source": [
    "# MistralRS\n",
    "https://github.com/EricLBuehler/mistral.rs\n",
    "\n",
    "~/mistral.rs/target/release/mistralrs-server --port 8000 --isq Q5_1 --no-paged-attn --prefix-cache-n 0  plain -m meta-llama/Llama-3.1-8B-Instruct -a llama\n",
    "\n",
    "# vLLM\n",
    "https://github.com/vllm-project/vllm\n",
    "\n",
    "vllm serve --port 8000  --gpu-memory-utilization 0.3 --max_model_len 30000 --quantization bitsandbytes --load_format bitsandbytes  meta-llama/Llama-3.1-8B-Instruct"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "764e9ec0-1e1b-4d16-96be-77350298b854",
   "metadata": {},
   "source": [
    "### Additional helper functions "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "daf4e4f6-09ef-4254-962c-951b2bae8f43",
   "metadata": {},
   "outputs": [],
   "source": [
    "def process(row, manual = True):\n",
    "    \n",
    "    if manual:\n",
    "        row[\"prompt\"] =  f'<|begin_of_text|><|start_header_id|>user<|end_header_id|>\\n\\n{row[\"prompt\"]}<|eot_id|>'\n",
    "        row[\"chosen\"] =  f'<|start_header_id|>assistant<|end_header_id|>\\n\\n{row[\"chosen\"]}<|eot_id|>'\n",
    "        row[\"rejected\"] =f'<|start_header_id|>assistant<|end_header_id|>\\n\\n{row[\"rejected\"]}<|eot_id|>'\n",
    "    else:\n",
    "        row[\"prompt\"] = tokenizer.apply_chat_template   ([ {\"role\": \"user\", \"content\":row[\"prompt\"]}],tokenize=False,add_generation_prompt=False )\n",
    "        row[\"chosen\"] = tokenizer.apply_chat_template   ([ {\"role\": \"assistant\", \"content\":row[\"chosen\"]}],tokenize=False,add_generation_prompt=False )\n",
    "        row[\"rejected\"] = tokenizer.apply_chat_template ( [ {\"role\": \"assistant\", \"content\":row[\"rejected\"]}],tokenize=False,add_generation_prompt=False )\n",
    " \n",
    "    return {'prompt': row[\"prompt\"], 'chosen': row[\"chosen\"], 'rejected': row[\"rejected\"], }\n",
    "\n",
    "\n",
    "def generate_dataset(generate_GPT, index, topics=None, only_include_wrong_answers=False, #if set True, we'll only include wrong answers. \n",
    "                     n_questions_for_each=1,  #how many questions for each topic\n",
    "                     number_nodes_to_get=2,   #how many nodes to make Q-A pair\n",
    "                     \n",
    "                     verbatim=False,get_rejected_from_trained_model=True,model=None, tokenizer=None,\n",
    "                     nodes=None, text=None, process=None):\n",
    "    data = {\"prompt\": [], \"chosen\": [], \"rejected\": [], \"rejected_correct\": []}\n",
    "\n",
    "    if isinstance(topics, list): #topics provided as list of strings\n",
    "        for topic in tqdm(topics):\n",
    "            for _ in range(n_questions_for_each):\n",
    "                try:\n",
    "                    question, correct_response, response_trained_model = get_question_and_answers(generate=generate_GPT, \n",
    "                                                        index = index,\n",
    "                                                        topic=topic, get_rejected_from_trained_model=get_rejected_from_trained_model,\n",
    "                                                        number_nodes_to_get=number_nodes_to_get,  \n",
    "                                                        model=model, tokenizer=tokenizer,\n",
    "                                                    )\n",
    "    \n",
    "                    correct_answer=None\n",
    "                    \n",
    "                    if verbatim:\n",
    "                        print (\"-\"*64)\n",
    "                        print (\">Prompt: \", question)\n",
    "                        print (\">Correct response: \", correct_response)\n",
    "                        print (\">Response model: \", response_trained_model)\n",
    "                        print (\">Correct? \", correct_answer)\n",
    "                    if only_include_wrong_answers:\n",
    "                        correct_answer =False #is_answer_correct(generate_GPT, correct_response, response_trained_model)\n",
    "                    \n",
    "                        if correct_answer==False:\n",
    "                            #do not add if answer is correct\n",
    "                            data[\"prompt\"].append(question)\n",
    "                            data[\"chosen\"].append(correct_response)\n",
    "                            data[\"rejected\"].append(response_trained_model)\n",
    "                            data[\"rejected_correct\"].append (correct_answer)\n",
    "                    else:\n",
    "                        data[\"prompt\"].append(question)\n",
    "                        data[\"chosen\"].append(correct_response)\n",
    "                        data[\"rejected\"].append(response_trained_model)\n",
    "                        data[\"rejected_correct\"].append (correct_answer)\n",
    "                except Exception as e:\n",
    "                    print(f\"An error occurred: {e}\")\n",
    "                    \n",
    "    else: #no topics provided, use random nodes\n",
    "        for _ in tqdm(range(topics)):\n",
    "            for _ in range(n_questions_for_each):\n",
    "                try:\n",
    "                    question, correct_response, response_trained_model = get_question_and_answers(generate=generate_GPT, \n",
    "                                                          index = index, get_rejected_from_trained_model=get_rejected_from_trained_model,\n",
    "                                                          number_nodes_to_get=number_nodes_to_get,  \n",
    "                                                          model=model, tokenizer=tokenizer,\n",
    "                                                    )\n",
    "        \n",
    "                    correct_answer=None\n",
    "                    if verbatim:\n",
    "                        print (\"-\"*64)\n",
    "                        print (\">Prompt: \", question)\n",
    "                        print (\">Correct response: \", correct_response)\n",
    "                        print (\">Response model: \", response_trained_model)\n",
    "                        print (\">Correct? \", correct_answer)\n",
    "                    if only_include_wrong_answers==False:\n",
    "                        \n",
    "                        correct_answer=False#is_answer_correct(generate_GPT, correct_response, response_trained_model)\n",
    "                        if correct_answer==False:\n",
    "                            #here do not add if answer is correct\n",
    "                            data[\"prompt\"].append(question)\n",
    "                            data[\"chosen\"].append(correct_response)\n",
    "                            data[\"rejected\"].append(response_trained_model)\n",
    "                            data[\"rejected_correct\"].append (correct_answer)\n",
    "                    else:\n",
    "                        data[\"prompt\"].append(question)\n",
    "                        data[\"chosen\"].append(correct_response)\n",
    "                        data[\"rejected\"].append(response_trained_model)\n",
    "                        data[\"rejected_correct\"].append (correct_answer)\n",
    "               \n",
    "                except Exception as e:\n",
    "                    print(f\"An error occurred: {e}\")                    \n",
    "    \n",
    "    hf_dataset = datasets.Dataset.from_dict(data)\n",
    "    \n",
    "    if process!=None:\n",
    "        hf_dataset = hf_dataset.map(\n",
    "            process,\n",
    "            num_proc=multiprocessing.cpu_count(),\n",
    "        )\n",
    "        \n",
    "    return hf_dataset\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ab1dba64-57b7-4008-b965-6f697f0b4d7f",
   "metadata": {},
   "source": [
    "### Set up Llama Index for RAG, embeddings, and other tools "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3767786e-07b2-4c06-b6fe-cce0b9bd4046",
   "metadata": {},
   "outputs": [],
   "source": [
    "Settings.embed_model = HuggingFaceEmbedding(\n",
    "    model_name=\"BAAI/bge-large-en-v1.5\"\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cd59092f-630e-4393-90fa-8d6f115cdebb",
   "metadata": {
    "scrolled": true,
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Load your dataset\n",
    "dataset = datasets.load_dataset(raw_dataset)['train']\n",
    "documents = [Document(text=dataset[i]['text']) for i in range (len (dataset))]\n",
    "\n",
    "pipeline = IngestionPipeline(\n",
    "    transformations=[\n",
    "        SentenceSplitter(chunk_size=1024, chunk_overlap=20),\n",
    "    ],\n",
    "   )\n",
    "nodes = pipeline.run(documents=documents,  show_progress=True,)\n",
    "index = VectorStoreIndex(nodes, show_progress=True,)\n",
    "retriever = index.as_retriever()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3545050f-36d3-4fa9-9c0a-621d92119486",
   "metadata": {},
   "source": [
    "### Load base model and create trainable version"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "39550e8f-0f9b-418c-b01c-cf780670d66b",
   "metadata": {},
   "outputs": [],
   "source": [
    "device='cuda:0'\n",
    "\n",
    "model_name='meta-llama/Llama-3.2-3B-Instruct'\n",
    "\n",
    "torch.cuda.empty_cache()\n",
    "\n",
    "try:\n",
    "    del model\n",
    "    del tokenizer\n",
    "except:\n",
    "    print ()\n",
    "gc.collect()\n",
    "torch.cuda.empty_cache()\n",
    "try:\n",
    "    del ref_model\n",
    "     \n",
    "except:\n",
    "    print ()\n",
    "gc.collect()\n",
    "torch.cuda.empty_cache()\n",
    "\n",
    "model = AutoModelForCausalLM.from_pretrained(\n",
    "    model_name,\n",
    "    trust_remote_code=True,\n",
    "    use_cache=False,\n",
    "     \n",
    "    device_map=\"auto\",\n",
    "    torch_dtype =torch.bfloat16,\n",
    "    attn_implementation=\"flash_attention_2\",\n",
    "    #device_map=\"cuda:0\",\n",
    ").to (device)\n",
    "model.config.use_cache = False\n",
    "\n",
    "model_name_tokenizer='lamm-mit/meta-llama-Meta-Llama-3.2-3B-Instruct-scratchpadtokenizer'\n",
    "tokenizer = AutoTokenizer.from_pretrained(model_name_tokenizer, trust_remote_code=True,\n",
    "                                           use_fast=False,\n",
    "                                         )\n",
    "pad_token='<|finetune_right_pad_id|>'\n",
    "tokenizer.pad_token = pad_token\n",
    "tokenizer.padding_side = \"right\"  \n",
    "\n",
    "if use_LoRA:\n",
    "    from peft import LoraConfig, get_peft_model\n",
    "\n",
    "    lora_alpha = 64\n",
    "    lora_dropout = 0.1\n",
    "    lora_r = 64   \n",
    "    peft_config = LoraConfig(\n",
    "        lora_alpha=lora_alpha,\n",
    "        lora_dropout=lora_dropout,\n",
    "        r=lora_r,\n",
    "        bias=\"none\",\n",
    "        task_type=\"CAUSAL_LM\",#[\"q_proj\", \"v_proj\", \"k_proj\", \"o_proj\", \"gate_proj\"]\n",
    "        target_modules=[\n",
    "            \"q_proj\",\n",
    "            \"k_proj\",\n",
    "            \"v_proj\",\n",
    "            \"o_proj\",\n",
    "            \"gate_proj\",\n",
    "            \"up_proj\",\n",
    "            \"down_proj\",\n",
    "            \"embed_tokens\",\n",
    "            \"lm_head\",\n",
    "        ],\n",
    "    ) \n",
    "    model=get_peft_model(model, peft_config)\n",
    "    \n",
    "    model.print_trainable_parameters()\n",
    "    ref_model=None\n",
    "else:\n",
    "    ref_model=AutoModelForCausalLM.from_pretrained(\n",
    "        model_name,\n",
    "        trust_remote_code=True,\n",
    "        use_cache=False,\n",
    "         \n",
    "        device_map=\"auto\",\n",
    "        torch_dtype =torch.bfloat16,\n",
    "        attn_implementation=\"flash_attention_2\",\n",
    "         \n",
    "    ).to (device)\n",
    "    ref_model.config.use_cache = False\n",
    "\n",
    "tokenizer.encode (f'{think_start}{think_end}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "82533cf9-128f-4a4e-b163-8d870b6d902b",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# Setting up default values for the API key, model, and organization\n",
    "generate_GPT_MistralRS = partial(\n",
    "    generate_OpenAI,\n",
    "    openai_api_key='NONE',   \n",
    "    model='meta-llama/Llama-3.1-8B-Instruct',\n",
    "    base_url=\"http://localhost:8000/v1\"\n",
    "   )\n",
    "\n",
    "prompt='What is spider silk?'\n",
    "messages=[\n",
    "            {\n",
    "                \"role\": \"system\",\n",
    "                \"content\": 'You are a materials scientist.',\n",
    "            },\n",
    "            {\n",
    "                \"role\": \"user\",\n",
    "                \"content\": prompt,\n",
    "            }\n",
    "        ] \n",
    "\n",
    "res, _ = generate_GPT_MistralRS (messages=messages)\n",
    "res"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a5de82e8-e5f0-4af6-aaa2-ed49fadfd338",
   "metadata": {},
   "source": [
    "### Define functions to generate dataset on-the-fly"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "343aeb6e-932f-48d7-bddb-be189bd9bcfc",
   "metadata": {},
   "outputs": [],
   "source": [
    "        \n",
    "def get_random_nodes(index, number_nodes_to_get=5):\n",
    "    # Get all nodes from the index\n",
    "    all_nodes = list(index.docstore.docs.values())\n",
    "    \n",
    "    # Ensure we don't request more nodes than exist in the index\n",
    "    number_nodes_to_get = min(number_nodes_to_get, len(all_nodes))\n",
    "    \n",
    "    # Randomly select N nodes\n",
    "    random_nodes = random.sample(all_nodes, number_nodes_to_get)\n",
    "    \n",
    "    # Concatenate their text\n",
    "    concatenated_text = \" \".join([node.text for node in random_nodes])\n",
    "    \n",
    "    return random_nodes, concatenated_text\n",
    "\n",
    "\n",
    "def get_question_and_answers(\n",
    "    generate,\n",
    "    index,\n",
    "    topic=None,\n",
    "    number_nodes_to_get=2,\n",
    "    nodes=None,\n",
    "    text=None,\n",
    "    get_rejected_from_trained_model=True,\n",
    "    model=None,\n",
    "    tokenizer=None,\n",
    "    use_rag=True,\n",
    "    categories=None,  # Categories can be passed in\n",
    "):\n",
    "    \"\"\"\n",
    "    Generates a question and its corresponding correct and rejected answers.\n",
    "\n",
    "    Parameters:\n",
    "    - generate_fn: Function to generate responses based on messages.\n",
    "    - index: The index used for node retrieval and RAG.\n",
    "    - topic: The topic for which to generate the question.\n",
    "    - number_nodes_to_get: Number of nodes to retrieve if topic is provided.\n",
    "    - nodes: Specific nodes to use as context.\n",
    "    - text: Specific text to use as context.\n",
    "    - get_rejected_from_trained_model: Flag to generate a rejected answer using a trained model.\n",
    "    - model: The trained model for generating rejected answers.\n",
    "    - tokenizer: The tokenizer associated with the trained model.\n",
    "    - use_rag: Flag to enable RAG for enhancing the correct answer.\n",
    "    - categories: List of categories to extract; defaults to standard values if None.\n",
    "\n",
    "    Returns:\n",
    "    - question_with_scratchpad: The generated question appended with a scratchpad placeholder.\n",
    "    - correct_response: The enhanced correct answer including the structured scratchpad.\n",
    "    - rejected_answer: The rejected answer.\n",
    "    \"\"\"\n",
    "\n",
    "    # Set default categories if none provided\n",
    "    if categories is None:\n",
    "        categories = [\n",
    "            \"Reasoning Steps\",\n",
    "            \"Relevant Materials or Concepts\",\n",
    "            \"Design Principles\",\n",
    "            \"Material Properties\",\n",
    "            #\"Contradictions or Counterexamples\",\n",
    "            \"Hypothesis\",\n",
    "            #\"Unique Facts\",\n",
    "            #\"Philosophical Aspects\",\n",
    "            #\"Logical Considerations\",\n",
    "        ]\n",
    "\n",
    "    # Retrieve or set the concatenated context text\n",
    "    context = retrieve_context(index, topic, number_nodes_to_get, nodes, text)\n",
    "\n",
    "    # Generate the question\n",
    "    question = generate_question(generate, context)\n",
    "\n",
    "    # Enhance the context using RAG if enabled\n",
    "    enriched_context = (\n",
    "        enhance_context_with_rag(index, question, context) if use_rag else context\n",
    "    )\n",
    "\n",
    "    # Extract information for each category\n",
    "    extracted_info = extract_categories(generate, categories, question, enriched_context,\n",
    "                                        add_RAG=True,\n",
    "                                        #index\n",
    "                                       )\n",
    "\n",
    "    # Generate reasoning steps based on the extracted information\n",
    "    reasoning_steps=''\n",
    "    # Assemble the single structured scratchpad\n",
    "    scratchpad = assemble_scratchpad(extracted_info, reasoning_steps)\n",
    "\n",
    "    # Generate the correct answer\n",
    "    correct_response = generate_correct_answer(\n",
    "        generate, question, enriched_context\n",
    "    )\n",
    "\n",
    "    # Combine the scratchpad and the answer manually\n",
    "    correct_response_with_scratchpad = f\"{scratchpad}\\n{correct_response}\"\n",
    "\n",
    "    # Prepare the question (no need to instruct about scratchpad inclusion)\n",
    "    question_with_scratchpad = question\n",
    "\n",
    "    # Generate the rejected (incorrect) response\n",
    "    rejected_answer = generate_rejected_answer(\n",
    "        generate, question, get_rejected_from_trained_model, model, tokenizer\n",
    "    )\n",
    "\n",
    "    return question_with_scratchpad+f' Use {think_start}.', correct_response_with_scratchpad, rejected_answer\n",
    "\n",
    "\n",
    "def retrieve_context(index, topic, number_nodes_to_get, nodes, text):\n",
    "    if nodes is None and text is None:\n",
    "        if topic:\n",
    "            _, concatenated_text = get_nodes_for_topic(index, topic, number_nodes_to_get)\n",
    "        else:\n",
    "            _, concatenated_text = get_random_nodes(index, number_nodes_to_get)\n",
    "    else:\n",
    "        concatenated_text = text or \" \".join([node.text for node in nodes])\n",
    "    token_length=len(tokenizer.encode(concatenated_text))\n",
    "    print (\"Token length of tokenized node data: \", token_length)\n",
    "    return concatenated_text\n",
    "\n",
    "\n",
    "def generate_question(generate_fn, context):\n",
    "    question_gen_query = (\n",
    "        \"You are a Teacher/Professor. Your task is to setup \"\n",
    "        \"a quiz/examination. Using information in the provided context, formulate \"\n",
    "        \"a single question that captures an important fact from the \"\n",
    "        \"context. Restrict the question to the context information provided, \"\n",
    "        \"and make sure this is a question that a highly trained domain expert can answer without seeing the context.\\n\\n\"\n",
    "        \"Just return the question, nothing else. Do not refer to the context, a paper, names, or authors, just ask the question. \"\n",
    "        \"Do not refer to names, persons, or specific text/context. \"\n",
    "        \"The question must be challenging, deep, and stand on its own and query facts and expert domain knowledge. \"\n",
    "        \"The question must NOT refer to a study, or paper, or a specific author.\"\n",
    "    )\n",
    "\n",
    "    messages = [\n",
    "        {\"role\": \"system\", \"content\": 'You are a materials scientist.'},\n",
    "        {\n",
    "            \"role\": \"user\",\n",
    "            \"content\": f\"{question_gen_query}\\n\\nContext: {context}\",\n",
    "        },\n",
    "    ]\n",
    "    question, _ = generate_fn(messages=messages, temperature=0.7)\n",
    "    return question.strip()\n",
    "\n",
    "\n",
    "def enhance_context_with_rag(index, question, context):\n",
    "    query_engine = index.as_query_engine()\n",
    "    answer = query_engine.query(f\"{question}\\n\\nProvide detailed context and reasoning.\")\n",
    "    enriched_context = f\"{context}\\nAdditional Information: {answer.response}\"\n",
    "    return enriched_context\n",
    "\n",
    "\n",
    "def extract_categories(generate_fn, categories, question, context, index=None, add_RAG=False):\n",
    "    extracted_info = {}\n",
    "    for category in categories:\n",
    "        prompt = f\"\"\"\n",
    "Based on the context, extract the \"{category}\" relevant to the question, keep it brief.\n",
    "\n",
    "Question: {question}\n",
    "\n",
    "Context: {context}\n",
    "\n",
    "Provide only the \"{category}\" without additional explanations.\n",
    "\n",
    "If you cannot find any, respond with an empty string. Keep the answer brief, but use step-by-step reasoning and a clear explanation. \n",
    "\n",
    "Just provide the answer, do not refer to the context.\n",
    "\"\"\"\n",
    "        messages = [\n",
    "            {\"role\": \"system\", \"content\": 'You are a helpful assistant who provides well-reasoned, but succinct responses. Act like a professor.'},\n",
    "            {\"role\": \"user\", \"content\": prompt},\n",
    "        ]\n",
    "        response, _ = generate_fn(messages=messages)\n",
    "        if index != None:\n",
    "            prompt = f\"\"\"\n",
    "Use the draft and improve the \"{category}\" relevant to the question.\n",
    "\n",
    "Question: {question}\n",
    "\n",
    "Draft: {response}\n",
    "\n",
    "Provide only the \"{category}\" without additional explanations.\n",
    "\n",
    "If you cannot find any, respond with an empty string. Keep the answer brief, but use step-by-step reasoning and a clear explanation. \n",
    "\n",
    "Just provide the answer, do not refer to the context.\n",
    "\"\"\"\n",
    "            response_RAG = query_engine.query(f\"{prompt}\")\n",
    "            print (\"Improve category with RAG\")\n",
    "            response=response_RAG\n",
    "        extracted_info[category] = response.strip()\n",
    "\n",
    "    if add_RAG:\n",
    "        prompt = f\"\"\"\n",
    "Give additional background relevant for answering the question\n",
    "\n",
    "Question: {question}\n",
    "\n",
    "Do not answer the question, just provide additional relevant information and insights. Keep it brief.\n",
    "\"\"\"\n",
    "        extracted_info['Additional Background']  = query_engine.query(f\"{prompt}\").response.strip()\n",
    "        \n",
    "    return extracted_info\n",
    "\n",
    "def assemble_scratchpad(extracted_info, reasoning_steps):\n",
    "    scratchpad = f\"{think_start}\\n\"\n",
    "    for category, content in extracted_info.items():\n",
    "        scratchpad += f\"**{category}**:\\n\\n{content}\\n\\n\"\n",
    "    scratchpad += f\"{think_end}\"\n",
    "    return scratchpad\n",
    "\n",
    "\n",
    "def generate_correct_answer(generate_fn, question, context):\n",
    "    prompt = f\"\"\"\n",
    "Using the context provided, answer the following question:\n",
    "\n",
    "Question: {question}\n",
    "\n",
    "Context: {context}\n",
    "\n",
    "Provide a comprehensive and accurate answer.\n",
    "\"\"\"\n",
    "    messages = [\n",
    "        {\"role\": \"system\", \"content\": 'You are a knowledgeable materials scientist.'},\n",
    "        {\"role\": \"user\", \"content\": prompt},\n",
    "    ]\n",
    "    answer, _ = generate_fn(messages=messages)\n",
    "    return answer.strip()\n",
    "\n",
    "\n",
    "def generate_rejected_answer(generate_fn, question, get_from_trained_model, model, tokenizer):\n",
    "    if get_from_trained_model:\n",
    "        # Implement logic to generate using the trained model\n",
    "        incorrect_answer, _ = generate_local_model(\n",
    "            model=model,\n",
    "            tokenizer=tokenizer,\n",
    "            prompt=f\"You provide the answer to: {question}\\nThe answer is:\",\n",
    "            system_prompt='You are a materials scientist.',\n",
    "        )\n",
    "    else:\n",
    "        prompt = f\"\"\"\n",
    "You are to provide an incorrect answer to the question below.\n",
    "\n",
    "Question: {question}\n",
    "\n",
    "Do not include any reasoning or refer back to the question.\n",
    "\n",
    "Just provide the incorrect answer.\n",
    "\"\"\"\n",
    "        messages = [\n",
    "            {\"role\": \"system\", \"content\": 'You are a materials scientist.'},\n",
    "            {\"role\": \"user\", \"content\": prompt},\n",
    "        ]\n",
    "        incorrect_answer, _ = generate_fn(messages=messages)\n",
    "    return incorrect_answer.strip()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ea420ff6-0f36-4b97-965e-144c7cdcc268",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# Example usage of the function\n",
    "question, correct_ans, rejected_ans=get_question_and_answers(generate=generate_GPT_MistralRS, model=model,\n",
    "                                                             tokenizer=tokenizer, index=index, topic=None, \n",
    "                                                              \n",
    "                             number_nodes_to_get=3, nodes=None, text=None, \n",
    "                             get_rejected_from_trained_model=True,\n",
    "                                                            )\n",
    "\n",
    "print(\"Question:\")\n",
    "print(question)\n",
    "print(\"\\nCorrect Answer with THINKING:\")\n",
    "print(correct_ans)\n",
    "print(\"\\nRejected Answer:\")\n",
    "print(rejected_ans)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0321b119-428b-4180-aeea-11854efc07a8",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# Setting up default values for the API key, model, and organization\n",
    "generate_GPT_local = partial(\n",
    "    generate_local_model,\n",
    "    model=model, tokenizer=tokenizer,\n",
    ")\n",
    "\n",
    "prompt=f'What is spider silk? Use a {think_start}.'\n",
    "messages=[\n",
    "            {\n",
    "                \"role\": \"system\",\n",
    "                \"content\": 'You are a materials scientist.',\n",
    "            },\n",
    "            {\n",
    "                \"role\": \"user\",\n",
    "                \"content\": prompt,\n",
    "            }\n",
    "        ] \n",
    "\n",
    "res, _ = generate_GPT_local (messages=messages,max_new_tokens=128, #prepend_response=f'<|thinking|>',\n",
    "                            )\n",
    "res"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "53bc3678-4045-42f6-8286-ab400706a159",
   "metadata": {},
   "source": [
    "### Phase I: Structured Thought Integration Training "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d7aef3c9-5086-4d73-a8ca-c33145b6d933",
   "metadata": {},
   "outputs": [],
   "source": [
    "FT_model_name='Phase_I_results'\n",
    "model_current=FT_model_name+'_'\n",
    "\n",
    "#How many topics are generated in each training step\n",
    "topics= 50\n",
    "\n",
    "#How many questions per topic \n",
    "num_questions_per_topic=1\n",
    "\n",
    "#How many epochs trained in each training step\n",
    "num_epochs_per_dataset_generation=3\n",
    "\n",
    "max_prompt_length=512\n",
    "max_length=1024\n",
    "\n",
    "###############################################\n",
    "cfg =  ORPOConfig(\n",
    "    output_dir=FT_model_name,               # usual HF Trainer args: https://huggingface.co/docs/transformers/main_classes/trainer#transformers.Trainer.args\n",
    "    num_train_epochs=1,                     # number of training epochs\n",
    "    per_device_train_batch_size=1,          # batch size per device during training\n",
    "    gradient_accumulation_steps=2,          # number of steps before performing a backward/update pass\n",
    "    gradient_checkpointing=True,            # use gradient checkpointing to save memory\n",
    "    optim=\"adamw_torch_fused\",              # use fused adamw optimizer\n",
    "    logging_steps=10,                       # log every .. steps\n",
    "    bf16=True,                              # use bfloat16 precision\n",
    "    #tf32=True,                             # use tf32          \n",
    "    learning_rate=5e-5,                     # learning rate\n",
    "    warmup_ratio=0,\n",
    "    warmup_steps=0,\n",
    "    #lr_scheduler_type=\"cosine\",\n",
    "    lr_scheduler_type=\"constant\",\n",
    "    max_prompt_length=max_prompt_length,\n",
    "    remove_unused_columns=False,\n",
    "    max_length=max_length,\n",
    "    beta=0.1,                               # ORPO beta\n",
    "    save_total_limit=3,                     # args related to saving the model...\n",
    "    #save_strategy=\"epoch\",\n",
    "    save_strategy=\"no\",\n",
    "    #push_to_hub=True,                       \n",
    "    hub_private_repo=True,\n",
    "    #report_to=['wandb'],                    # report metrics to Weights & Biases\n",
    "    hub_model_id=f'lamm-mit/{FT_model_name}',\n",
    ")\n",
    "###############################################"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1971cb1f-800b-4fde-970b-cee05dbce23f",
   "metadata": {},
   "outputs": [],
   "source": [
    "if isinstance(topics, list) and all(isinstance(t, str) for t in topics):\n",
    "    n_steps = len(topics) * num_questions_per_topic*num_epochs_per_dataset_generation\n",
    "else:\n",
    "    n_steps = topics * num_questions_per_topic*num_epochs_per_dataset_generation\n",
    "\n",
    "trainer = PRefLexORORPOTrainer(\n",
    "         model=model,\n",
    "         args=cfg,\n",
    "         train_dataset=None,\n",
    "         #train_dataset=temp,\n",
    "         tokenizer=tokenizer,\n",
    "         n_steps=n_steps,  # Train for 50 steps before updating dataset\n",
    "         #topics=topics,\n",
    "         topics=topics,\n",
    "         number_nodes_to_get=3,\n",
    "         n_questions_for_each=num_questions_per_topic,\n",
    "         only_include_wrong_answers=False, \n",
    "         process=process,\n",
    "         generate_dataset=generate_dataset,\n",
    "         generate=generate_GPT_MistralRS,  #generate_GPT_OpenAI,\n",
    "         index=index,\n",
    "         get_rejected_from_trained_model=True,\n",
    "        )\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "05a70355-2aee-40ab-8fc1-4e1b41307588",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "system_prompt='You are a materials scientist.'\n",
    "\n",
    "# Training loop\n",
    "num_iterations = 50\n",
    "for iteration in range(num_iterations):\n",
    "    print(f\"Starting iteration {iteration + 1}/{num_iterations}\")\n",
    "    \n",
    "    # Train for N steps\n",
    "    trainer.train()\n",
    "    \n",
    "    print (64*\"#\") \n",
    "    txt='Tell me why hierarchical structures work so well.'+f' Use {think_start}.'\n",
    "    #txt='What is the reported work of fracture of the nacre in the abalone shell compared to its mineral constituent?'\n",
    "    output_text, _ =generate_local_model (model=model, tokenizer=tokenizer,  prompt=txt,\n",
    "                                               system_prompt=system_prompt,   prepend_response=f'{think_start}',\n",
    "                                   num_return_sequences=1,  repetition_penalty=1.0, #top_p=top_p, top_k=top_k,  \n",
    "                                   temperature=.1,max_new_tokens=1024, messages = [], do_sample=True,\n",
    "                                   )\n",
    "    print (output_text)\n",
    "    print (64*\"-\")\n",
    "    txt=f'What is the relationship between materials and music?'+f' Use {think_start}.'\n",
    "    #txt='What is the reported work of fracture of the nacre in the abalone shell compared to its mineral constituent?'\n",
    "    output_text, messages =generate_local_model (model=model, tokenizer=tokenizer,  prompt=txt,\n",
    "                                               system_prompt=system_prompt,  prepend_response=f'{think_start}',\n",
    "                                   num_return_sequences=1,  repetition_penalty=1.0, #top_p=top_p, top_k=top_k,  \n",
    "                                   temperature=.1,max_new_tokens=1024, messages = [], do_sample=True,\n",
    "                                   )\n",
    "    print (output_text)\n",
    "    print (64*\"-\")\n",
    "    txt='Tell me why hierarchical structures work so well.'+f' Use {think_start}.'\n",
    "    #txt='What is the reported work of fracture of the nacre in the abalone shell compared to its mineral constituent?'\n",
    "    output_text, messages =generate_local_model (model=model, tokenizer=tokenizer,  prompt=txt,\n",
    "                                               system_prompt=system_prompt,  prepend_response=f'{think_start}',\n",
    "                                   num_return_sequences=1,  repetition_penalty=1.0, #top_p=top_p, top_k=top_k,  \n",
    "                                   temperature=.1,max_new_tokens=1024, messages = [], do_sample=True,\n",
    "                                   )\n",
    "    print (output_text)\n",
    "    print (64*\"#\")\n",
    "    \n",
    "    trainer.update_dataset()\n",
    "    \n",
    "    trainer.save_model(f\"./{model_current}\")\n",
    "    model.push_to_hub (f\"lamm-mit/{model_current}\", private=True)\n",
    "    tokenizer.push_to_hub (f\"lamm-mit/{model_current}\", private=True)\n",
    "\n",
    "    print(f\"Completed iteration {iteration + 1}/{num_iterations}\")\n",
    "\n",
    "    #trainer.update_dataset()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e3164528-9d0e-4e5e-8f71-2956f52e6647",
   "metadata": {},
   "source": [
    "### Phase II: Independent Reasoning Development\n",
    "\n",
    "#### First, merge adapter into base model"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "845d079d-4e91-4b59-b78b-c1fb2c6a6bb7",
   "metadata": {},
   "outputs": [],
   "source": [
    "from transformers import AutoModelForCausalLM, AutoTokenizer\n",
    "\n",
    "torch.cuda.empty_cache()\n",
    "import gc \n",
    "try:\n",
    "    del model\n",
    "    del tokenizer\n",
    "    del merged_model\n",
    "except:\n",
    "    print ()\n",
    "gc.collect()\n",
    "torch.cuda.empty_cache()\n",
    "try:\n",
    "    del ref_model\n",
    "     \n",
    "except:\n",
    "    print ()\n",
    "gc.collect()\n",
    "torch.cuda.empty_cache()\n",
    "\n",
    "model_name=\"lamm-mit/meta-llama-Llama-3.2-3B-Instruct-untied\"\n",
    "model_base = AutoModelForCausalLM.from_pretrained(model_name,     torch_dtype =torch.bfloat16,\n",
    "    attn_implementation=\"flash_attention_2\",device_map=\"auto\",trust_remote_code=True,\n",
    "    \n",
    "     )\n",
    " \n",
    "peft_model_id = model_current\n",
    "\n",
    "model_base = PeftModel.from_pretrained(model_base, peft_model_id)\n",
    "\n",
    "model = model_base.merge_and_unload()\n",
    "\n",
    "model_name_tokenizer='lamm-mit/meta-llama-Meta-Llama-3.2-3B-Instruct-scratchpadtokenizer'\n",
    "#model_name_tokenizer=model_name\n",
    "tokenizer = AutoTokenizer.from_pretrained(model_name_tokenizer, trust_remote_code=True,\n",
    "                                           use_fast=False,\n",
    "                                         )\n",
    "pad_token='<|finetune_right_pad_id|>'\n",
    "tokenizer.pad_token = pad_token\n",
    "tokenizer.padding_side = \"right\"  \n",
    "\n",
    "torch.cuda.empty_cache()\n",
    "try:\n",
    "    del model_base\n",
    "     \n",
    "except:\n",
    "    print ()\n",
    "gc.collect()\n",
    "torch.cuda.empty_cache()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "db03a16a-8648-47a8-bb67-b66f86c07237",
   "metadata": {},
   "outputs": [],
   "source": [
    "if use_LoRA:\n",
    "\n",
    "    from peft import LoraConfig, get_peft_model\n",
    "    lora_alpha = 64\n",
    "    lora_dropout = 0.1\n",
    "    lora_r = 64\n",
    "\n",
    "    peft_config = LoraConfig(\n",
    "        lora_alpha=lora_alpha,\n",
    "        lora_dropout=lora_dropout,\n",
    "        r=lora_r,\n",
    "        bias=\"none\",\n",
    "        task_type=\"CAUSAL_LM\", \n",
    "        target_modules=[\n",
    "            \"q_proj\",\n",
    "            \"k_proj\",\n",
    "            \"v_proj\",\n",
    "            \"o_proj\",\n",
    "            \"gate_proj\",\n",
    "            \"up_proj\",\n",
    "            \"down_proj\",\n",
    "            #\"embed_tokens\",\n",
    "            #\"lm_head\",\n",
    "        ], \n",
    "      #  modules_to_save=[\"embed_tokens\", \"lm_head\"]\n",
    "    ) \n",
    "    \n",
    "    from peft import prepare_model_for_kbit_training, LoraConfig, get_peft_model\n",
    "    \n",
    "    #model = prepare_model_for_kbit_training(model)\n",
    "    model=get_peft_model(model, peft_config)\n",
    "    \n",
    "    model.print_trainable_parameters()\n",
    "    ref_model=None\n",
    "else:\n",
    "    print (\"We will not use LoRA\")\n",
    "\n",
    "    ref_model=AutoModelForCausalLM.from_pretrained(\n",
    "        model_name,\n",
    "        trust_remote_code=True,\n",
    "        use_cache=False,\n",
    "         \n",
    "        device_map=\"auto\",\n",
    "        torch_dtype =torch.bfloat16,\n",
    "        attn_implementation=\"flash_attention_2\",\n",
    "        #device_map=\"cuda:0\",\n",
    "    ).to (device)\n",
    "    ref_model.config.use_cache = False\n",
    "\n",
    "tokenizer.encode ('<|thinking|><|/thinking|><|scratchpad|><|/scratchpad|><|reflect|><|/reflect|><|response|><|/response|>')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5ac9d4bb-5e08-46b3-bc34-9d40d0febe4c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Setting up default values for the API key, model, and organization\n",
    "generate_GPT_local = partial(\n",
    "    generate_local_model,\n",
    "    model=model, tokenizer=tokenizer,\n",
    ")\n",
    "\n",
    "prompt=f'What is spider silk? Use a {think_start}.'\n",
    "messages=[\n",
    "            {\n",
    "                \"role\": \"system\",\n",
    "                \"content\": 'You are a materials scientist.',\n",
    "            },\n",
    "            {\n",
    "                \"role\": \"user\",\n",
    "                \"content\": prompt,\n",
    "            }\n",
    "        ] \n",
    "\n",
    "res, _ = generate_GPT_local (messages=messages,max_new_tokens=128, #prepend_response=f'<|thinking|>',\n",
    "                            )\n",
    "res"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "81cf7150-e33b-431d-af44-f19624200e40",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "txt='Tell me why hierarchical structures work so well.'+f' Use {think_start}.'\n",
    "\n",
    "output_text, _ =generate_local_model (model=model, tokenizer=tokenizer,  prompt=txt,\n",
    "                                           system_prompt='',   #prepend_response=f'{think_start}',\n",
    "                               num_return_sequences=1,  repetition_penalty=1.0, #top_p=top_p, top_k=top_k,  \n",
    "                               temperature=.01,max_new_tokens=1024, messages = [], do_sample=True,\n",
    "                               )\n",
    "print (output_text)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e58ec3df-f389-45cf-beb0-a10ee7b18d34",
   "metadata": {
    "scrolled": true
   },
   "source": [
    "#### Set up PRefLexORDPOTrainer for Phase II"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d2692414-5912-48ee-a31b-e7a6f3948fa0",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "FT_model_name='Phase_II_results'\n",
    "model_current=FT_model_name+'_'\n",
    "\n",
    "max_prompt_length=512\n",
    "max_length=1024\n",
    "\n",
    "class RewardLoggingCallback(TrainerCallback):\n",
    "    def on_log(self, args, state, control, logs=None, **kwargs):\n",
    "        if state.log_history:\n",
    "            try:\n",
    "                print ( f\"Step={state.log_history[-1]['step'] }\", \"rewards/margins=\", state.log_history[-1]['rewards/margins'] ,\n",
    "                      \"loss=\", state.log_history[-1]['loss'],   \"rewards/accuracy=\", state.log_history[-1]['rewards/accuracies'] )# Get the last log entry\n",
    "            except:\n",
    "                print (end='')\n",
    " \n",
    "cfg = DPOConfig(\n",
    "    output_dir=FT_model_name,     # usual HF Trainer args: https://huggingface.co/docs/transformers/main_classes/trainer#transformers.Trainer.args\n",
    "    num_train_epochs=1,                     # number of training epochs\n",
    "    per_device_train_batch_size=1,          # batch size per device during training\n",
    "    gradient_accumulation_steps=2,          # number of steps before performing a backward/update pass\n",
    "    gradient_checkpointing=False,            # use gradient checkpointing to save memory\n",
    "    optim=\"adamw_torch_fused\",              # use fused adamw optimizer\n",
    "    logging_steps=10,                       # log every .. steps\n",
    "    bf16=True,                              # use bfloat16 precision\n",
    "    #tf32=True,                             # use tf32          \n",
    "    max_grad_norm=0.3,\n",
    "    learning_rate=1e-6,                     # learning rate\n",
    "    warmup_ratio=0,\n",
    "    warmup_steps=0,\n",
    "    #lr_scheduler_type=\"cosine\",\n",
    "    lr_scheduler_type=\"constant\",\n",
    "    max_prompt_length=512,\n",
    "    max_length=2000,\n",
    "    remove_unused_columns=False,\n",
    "    #max_length=1024,\n",
    "    beta=0.5,                               # ORPO beta\n",
    "    save_total_limit=50,                     # args related to saving the model...\n",
    "    save_strategy=\"epoch\",\n",
    "    #push_to_hub=True,                       \n",
    "    hub_private_repo=True,\n",
    "    report_to=['none'],                    # report metrics to Weights & Biases\n",
    "    hub_model_id=f'lamm-mit/{FT_model_name}',\n",
    "    loss_type=\"exo_pair\",                  # Loss type for DPO\n",
    "    label_smoothing=5e-3,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "55f0ffa6-766e-4433-b265-4a1bd1c43181",
   "metadata": {},
   "source": [
    "#### Define new function to generate rejected answer using current model "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "479265fe-c875-46cb-8b1f-c984b6ae6327",
   "metadata": {},
   "outputs": [],
   "source": [
    "def generate_rejected_answer(generate_fn, question, get_from_trained_model, model, tokenizer):\n",
    "    \n",
    "    if get_from_trained_model:\n",
    "    incorrect_answer, _ = generate_local_model(\n",
    "            model=model,\n",
    "            tokenizer=tokenizer,\n",
    "            prompt=f\"{question}\"+f' Use {think_start}.',\n",
    "            system_prompt='You are a materials scientist.', max_new_tokens=1500,\n",
    "        )\n",
    "    else:\n",
    "        prompt = f\"\"\"\n",
    "You are to provide an incorrect answer to the question below.\n",
    "\n",
    "Question: {question}\n",
    "\n",
    "Do not include any reasoning or refer back to the question.\n",
    "\n",
    "Just provide the incorrect answer.\n",
    "\"\"\"\n",
    "        messages = [\n",
    "            {\"role\": \"system\", \"content\": 'You are a materials scientist.'},\n",
    "            {\"role\": \"user\", \"content\": prompt},\n",
    "        ]\n",
    "        incorrect_answer, _ = generate_fn(messages=messages)\n",
    "    return incorrect_answer.strip()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "419cdac3-003f-4f64-ae5d-ba3c116b2b66",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "# Example usage  \n",
    "\n",
    "question, correct_ans, rejected_ans=get_question_and_answers(generate=generate_GPT_MistralRS, model=model,\n",
    "                                                             tokenizer=tokenizer, index=index, topic=None, #'spider silk strength', \n",
    "                             number_nodes_to_get=3, nodes=None, text=None,  \n",
    "                             get_rejected_from_trained_model=True,\n",
    "                                                            )\n",
    "\n",
    "print(\"Question:\")\n",
    "print(question)\n",
    "print(\"\\nCorrect Answer with THINKING:\")\n",
    "print(correct_ans)\n",
    "print(\"\\nRejected Answer:\")\n",
    "print(rejected_ans)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6b140406-05b9-4938-81ac-92964f1a8245",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "from datasets import load_dataset, concatenate_datasets\n",
    "\n",
    "topics= 50\n",
    "num_questions_per_topic=1\n",
    "num_epochs_per_dataset_generation=1\n",
    "\n",
    "if isinstance(topics, list) and all(isinstance(t, str) for t in topics):\n",
    "    n_steps = len(topics) * num_questions_per_topic*num_epochs_per_dataset_generation\n",
    "else:\n",
    "    n_steps = topics * num_questions_per_topic*num_epochs_per_dataset_generation\n",
    "\n",
    "trainer = PRefLexORDPOTrainer(\n",
    "        model=model,\n",
    "        ref_model=ref_model, # set to none if use LoRA\n",
    "        args=cfg,\n",
    "\n",
    "        train_dataset=None, \n",
    "        tokenizer=tokenizer,\n",
    "        n_steps=n_steps,  # Train for 50 steps before updating dataset\n",
    "        topics=topics,\n",
    "        number_nodes_to_get=3,\n",
    "        n_questions_for_each=num_questions_per_topic,\n",
    "        only_include_wrong_answers=False, \n",
    "        process=process,\n",
    "    generate_dataset=generate_dataset,\n",
    "    generate=generate_GPT_MistralRS, #generate_GPT_OpenAI,\n",
    "    get_rejected_from_trained_model=True,\n",
    "    index=index,\n",
    "\n",
    "    #OPTION 1: Only include answer in loss\n",
    "    dynamic_answer_comparison = True,  \n",
    "    \n",
    "    #OPTION 2: Mask out all sections of thinking, to a degree (percentage indicates how much is randomly masked out)\n",
    "    mask_thinking_tokens = False, \n",
    "    thinking_token_mask_percentage = .2,  # Default to masking 100% of thinking tokens\n",
    "\n",
    "    think_start_token= '<|thinking|>', think_end_token= '<|/thinking|>',\n",
    "    include_thinking_token_in_labels=True,\n",
    "    callbacks=[RewardLoggingCallback()],\n",
    "\n",
    "    )\n",
    " "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "90fb3e5a-7b94-497a-bafe-65735ccddf97",
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "system_prompt='You are a materials scientist.'\n",
    "\n",
    "# Training loop\n",
    "num_iterations = 50\n",
    "\n",
    "for iteration in range(num_iterations):\n",
    "    print(f\"Starting iteration {iteration + 1}/{num_iterations}\")\n",
    "    \n",
    "    # Train for N steps\n",
    "    trainer.train()\n",
    "        \n",
    "    print (64*\"#\")\n",
    "    # Update dataset\n",
    "    txt='Tell me why hierarchical structures work so well.'#+f' Use {think_start}.'\n",
    "    #txt='What is the reported work of fracture of the nacre in the abalone shell compared to its mineral constituent?'\n",
    "    output_text, _ =generate_local_model (model=model, tokenizer=tokenizer,  prompt=txt,\n",
    "                                               system_prompt=system_prompt,   #prepend_response=f'{think_start}',\n",
    "                                   num_return_sequences=1,  repetition_penalty=1.0, #top_p=top_p, top_k=top_k,  \n",
    "                                   temperature=.1,max_new_tokens=1024, messages = [], do_sample=True,\n",
    "                                   )\n",
    "    print (output_text)\n",
    "    print (64*\"-\")\n",
    "    #trainer.update_dataset()\n",
    "    txt='Tell me why hierarchical structures work so well.'+f' Use {think_start}.'\n",
    "    #txt='What is the reported work of fracture of the nacre in the abalone shell compared to its mineral constituent?'\n",
    "    output_text, _ =generate_local_model (model=model, tokenizer=tokenizer,  prompt=txt,\n",
    "                                               system_prompt=system_prompt,   prepend_response=f'{think_start}',\n",
    "                                   num_return_sequences=1,  repetition_penalty=1.0, #top_p=top_p, top_k=top_k,  \n",
    "                                   temperature=.1,max_new_tokens=1024, messages = [], do_sample=True,\n",
    "                                   )\n",
    "    print (output_text)\n",
    "    print (64*\"-\")\n",
    "    txt='Explain the relationship between materials and music.'+f' Use {think_start}.'\n",
    "    #txt='What is the reported work of fracture of the nacre in the abalone shell compared to its mineral constituent?'\n",
    "    output_text, _ =generate_local_model (model=model, tokenizer=tokenizer,  prompt=txt,\n",
    "                                               system_prompt=system_prompt,   prepend_response=f'{think_start}',\n",
    "                                   num_return_sequences=1,  repetition_penalty=1.0, #top_p=top_p, top_k=top_k,  \n",
    "                                   temperature=.1,max_new_tokens=1024, messages = [], do_sample=True,\n",
    "                                   )\n",
    "    print (output_text) \n",
    "    print (64*\"#\")\n",
    "    \n",
    "    trainer.update_dataset()\n",
    "    \n",
    "    print(f\"Completed iteration {iteration + 1}/{num_iterations}\")\n",
    "\n",
    "    trainer.save_model(f\"./{model_current}\")\n",
    "    model.push_to_hub (f\"lamm-mit/{model_current}\", private=True)\n",
    "    tokenizer.push_to_hub (f\"lamm-mit/{model_current}\", private=True)    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5bd87c00-8ef1-4150-9f61-414741795eca",
   "metadata": {},
   "outputs": [],
   "source": [
    "trainer.save_model(f\"./{model_current}\")\n",
    "model.push_to_hub (f\"lamm-mit/{model_current}\", private=True)\n",
    "tokenizer.push_to_hub (f\"lamm-mit/{model_current}\", private=True)    "
   ]
  }
 ],
 "metadata": {
  "environment": {
   "kernel": "conda-base-py",
   "name": "workbench-notebooks.m123",
   "type": "gcloud",
   "uri": "us-docker.pkg.dev/deeplearning-platform-release/gcr.io/workbench-notebooks:m123"
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
